backend project

This commit is contained in:
Sone
2025-11-02 10:05:02 +01:00
parent e4199f65d8
commit deb622b796
62 changed files with 12475 additions and 0 deletions
+345
View File
@@ -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
View File
@@ -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();
});