backend project
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
export const firstNames = [
|
||||
"John",
|
||||
"Jane",
|
||||
"Michael",
|
||||
"Sarah",
|
||||
"David",
|
||||
"Emma",
|
||||
"Robert",
|
||||
"Olivia",
|
||||
"William",
|
||||
"Sophia",
|
||||
"James",
|
||||
"Emily",
|
||||
"Daniel",
|
||||
"Ava",
|
||||
"Matthew",
|
||||
"Mia",
|
||||
"Andrew",
|
||||
"Isabella",
|
||||
"Joseph",
|
||||
"Charlotte",
|
||||
"Thomas",
|
||||
"Amelia",
|
||||
"Anthony",
|
||||
"Harper",
|
||||
"Alexander",
|
||||
"Abigail",
|
||||
"Ryan",
|
||||
"Madison",
|
||||
"Tyler",
|
||||
"Elizabeth",
|
||||
"Nicholas",
|
||||
"Sofia",
|
||||
"Ethan",
|
||||
"Ella",
|
||||
"Brandon",
|
||||
"Grace",
|
||||
"Samuel",
|
||||
"Chloe",
|
||||
"Christian",
|
||||
"Victoria",
|
||||
"Noah",
|
||||
"Lily",
|
||||
"Christopher",
|
||||
"Hannah",
|
||||
"Justin",
|
||||
"Zoe",
|
||||
"Jonathan",
|
||||
"Natalie",
|
||||
"Benjamin",
|
||||
"Addison",
|
||||
"Kevin",
|
||||
"Leah",
|
||||
"Aaron",
|
||||
"Aubrey",
|
||||
"Timothy",
|
||||
"Audrey",
|
||||
"Richard",
|
||||
"Brooklyn",
|
||||
"Eric",
|
||||
"Bella",
|
||||
"Steven",
|
||||
"Claire",
|
||||
"Edward",
|
||||
"Skylar",
|
||||
"Charles",
|
||||
"Lucy",
|
||||
"Stephen",
|
||||
"Paisley",
|
||||
"Brian",
|
||||
"Evelyn",
|
||||
"Adam",
|
||||
"Anna",
|
||||
"Kyle",
|
||||
"Caroline",
|
||||
"Patrick",
|
||||
"Genesis",
|
||||
"Sean",
|
||||
"Autumn",
|
||||
"Jason",
|
||||
"Hailey",
|
||||
"Jeffrey",
|
||||
"Maya",
|
||||
"Marcus",
|
||||
"Kaylee",
|
||||
"Scott",
|
||||
"Riley",
|
||||
"Zachary",
|
||||
"Nora",
|
||||
"Nathan",
|
||||
"Ellie",
|
||||
"Paul",
|
||||
"Hazel",
|
||||
"Dustin",
|
||||
"Violet",
|
||||
];
|
||||
|
||||
// Additional generators for todos (shared with seed script)
|
||||
export const actionVerbs = [
|
||||
"Prepare",
|
||||
"Update",
|
||||
"Review",
|
||||
"Investigate",
|
||||
"Schedule",
|
||||
"Draft",
|
||||
"Analyze",
|
||||
"Refactor",
|
||||
"Migrate",
|
||||
"Optimize",
|
||||
"Validate",
|
||||
"Fix",
|
||||
"Design",
|
||||
"Document",
|
||||
"Monitor",
|
||||
];
|
||||
|
||||
export const subjects = [
|
||||
"monthly report",
|
||||
"system documentation",
|
||||
"user permissions",
|
||||
"training materials",
|
||||
"deployment pipeline",
|
||||
"error logs",
|
||||
"feature roadmap",
|
||||
"API responses",
|
||||
"database indices",
|
||||
"access controls",
|
||||
"notification service",
|
||||
"onboarding flow",
|
||||
"billing module",
|
||||
"cache strategy",
|
||||
"CI configuration",
|
||||
];
|
||||
|
||||
export const loremWords =
|
||||
"lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua".split(
|
||||
/\s+/
|
||||
);
|
||||
|
||||
export const lastNames = [
|
||||
"Smith",
|
||||
"Johnson",
|
||||
"Williams",
|
||||
"Brown",
|
||||
"Jones",
|
||||
"Miller",
|
||||
"Davis",
|
||||
"Garcia",
|
||||
"Rodriguez",
|
||||
"Wilson",
|
||||
"Martinez",
|
||||
"Anderson",
|
||||
"Taylor",
|
||||
"Thomas",
|
||||
"Hernandez",
|
||||
"Moore",
|
||||
"Martin",
|
||||
"Jackson",
|
||||
"Thompson",
|
||||
"White",
|
||||
"Lopez",
|
||||
"Lee",
|
||||
"Gonzalez",
|
||||
"Harris",
|
||||
"Clark",
|
||||
"Lewis",
|
||||
"Robinson",
|
||||
"Walker",
|
||||
"Perez",
|
||||
"Hall",
|
||||
"Young",
|
||||
"Allen",
|
||||
"Sanchez",
|
||||
"Wright",
|
||||
"King",
|
||||
"Scott",
|
||||
"Green",
|
||||
"Baker",
|
||||
"Adams",
|
||||
"Nelson",
|
||||
"Hill",
|
||||
"Ramirez",
|
||||
"Campbell",
|
||||
"Mitchell",
|
||||
"Roberts",
|
||||
"Carter",
|
||||
"Phillips",
|
||||
"Evans",
|
||||
"Turner",
|
||||
"Torres",
|
||||
"Parker",
|
||||
"Collins",
|
||||
"Edwards",
|
||||
"Stewart",
|
||||
"Flores",
|
||||
"Morris",
|
||||
"Nguyen",
|
||||
"Murphy",
|
||||
"Rivera",
|
||||
"Cook",
|
||||
"Rogers",
|
||||
"Morgan",
|
||||
"Peterson",
|
||||
"Cooper",
|
||||
"Reed",
|
||||
"Bailey",
|
||||
"Bell",
|
||||
"Gomez",
|
||||
"Kelly",
|
||||
"Howard",
|
||||
"Ward",
|
||||
"Cox",
|
||||
"Diaz",
|
||||
"Richardson",
|
||||
"Wood",
|
||||
"Watson",
|
||||
"Brooks",
|
||||
"Bennett",
|
||||
"Gray",
|
||||
"James",
|
||||
"Reyes",
|
||||
"Cruz",
|
||||
"Hughes",
|
||||
"Price",
|
||||
"Myers",
|
||||
"Long",
|
||||
"Foster",
|
||||
"Sanders",
|
||||
"Ross",
|
||||
"Morales",
|
||||
"Powell",
|
||||
"Sullivan",
|
||||
"Russell",
|
||||
"Ortiz",
|
||||
"Jenkins",
|
||||
"Perry",
|
||||
];
|
||||
|
||||
export const middleNames = [
|
||||
"John",
|
||||
"Jane",
|
||||
"Michael",
|
||||
"Sarah",
|
||||
"David",
|
||||
"Emma",
|
||||
"Robert",
|
||||
"Olivia",
|
||||
"William",
|
||||
"Sophia",
|
||||
];
|
||||
|
||||
export const phoneNumbers = [
|
||||
"123-456-7890",
|
||||
"987-654-3210",
|
||||
"555-555-5555",
|
||||
"111-222-3333",
|
||||
"444-555-6666",
|
||||
];
|
||||
|
||||
export const departments = [
|
||||
"IT",
|
||||
"Marketing",
|
||||
"Sales",
|
||||
"Finance",
|
||||
"Human Resources",
|
||||
"Operations",
|
||||
"Research and Development",
|
||||
"Customer Support",
|
||||
];
|
||||
|
||||
export const jobTitles = [
|
||||
"Software Engineer",
|
||||
"Product Manager",
|
||||
"Data Analyst",
|
||||
"UX Designer",
|
||||
"Marketing Specialist",
|
||||
"HR Manager",
|
||||
"Financial Analyst",
|
||||
"Sales Representative",
|
||||
"Customer Support",
|
||||
"Operations Manager",
|
||||
"Project Manager",
|
||||
"Business Analyst",
|
||||
"DevOps Engineer",
|
||||
"Quality Assurance",
|
||||
"Content Writer",
|
||||
"Graphic Designer",
|
||||
"Account Manager",
|
||||
"System Administrator",
|
||||
"Network Engineer",
|
||||
"Database Administrator",
|
||||
"Frontend Developer",
|
||||
"Backend Developer",
|
||||
"Full Stack Developer",
|
||||
"Mobile Developer",
|
||||
"UI Designer",
|
||||
"SEO Specialist",
|
||||
"Social Media Manager",
|
||||
"Technical Writer",
|
||||
"IT Support",
|
||||
"Security Analyst",
|
||||
];
|
||||
|
||||
export const adminTodoTasks = [
|
||||
{
|
||||
title: "Review new user applications",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Update system documentation",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Prepare monthly report",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Investigate user complaint",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Schedule team meeting",
|
||||
task: " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Approve content submissions",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Update user permissions",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Review security logs",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Create training materials",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
{
|
||||
title: "Follow up on escalated issues",
|
||||
task: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
|
||||
},
|
||||
];
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
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 = <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();
|
||||
});
|
||||
Reference in New Issue
Block a user