feat: Complete Z.CRM system with all 6 modules

 Features:
- Complete authentication system with JWT
- Dashboard with all 6 modules visible
- Contact Management module (Salesforce-style)
- CRM & Sales Pipeline module (Pipedrive-style)
- Inventory & Assets module (SAP-style)
- Tasks & Projects module (Jira/Asana-style)
- HR Management module (BambooHR-style)
- Marketing Management module (HubSpot-style)
- Admin Panel with user management and role matrix
- World-class UI/UX with RTL Arabic support
- Cairo font (headings) + Readex Pro font (body)
- Sample data for all modules
- Protected routes and authentication flow
- Backend API with Prisma + PostgreSQL
- Comprehensive documentation

🎨 Design:
- Color-coded modules
- Professional data tables
- Stats cards with metrics
- Progress bars and status badges
- Search and filters
- Responsive layout

📊 Tech Stack:
- Frontend: Next.js 14, TypeScript, Tailwind CSS
- Backend: Node.js, Express, Prisma
- Database: PostgreSQL
- Auth: JWT with bcrypt

🚀 Production-ready frontend with all features accessible
This commit is contained in:
Talal Sharabi
2026-01-06 18:43:43 +04:00
commit 35daa52767
82 changed files with 29445 additions and 0 deletions

349
backend/prisma/seed.ts Normal file
View File

@@ -0,0 +1,349 @@
import { PrismaClient } from '@prisma/client';
import bcrypt from 'bcryptjs';
const prisma = new PrismaClient();
async function main() {
console.log('🌱 Starting database seeding...');
// Create Departments
const salesDept = await prisma.department.create({
data: {
name: 'Sales Department',
nameAr: 'قسم المبيعات',
code: 'SALES',
description: 'Sales and Business Development',
},
});
const itDept = await prisma.department.create({
data: {
name: 'IT Department',
nameAr: 'قسم تقنية المعلومات',
code: 'IT',
description: 'Information Technology',
},
});
const hrDept = await prisma.department.create({
data: {
name: 'HR Department',
nameAr: 'قسم الموارد البشرية',
code: 'HR',
description: 'Human Resources',
},
});
console.log('✅ Created departments');
// Create Positions
const gmPosition = await prisma.position.create({
data: {
title: 'General Manager',
titleAr: 'المدير العام',
code: 'GM',
departmentId: salesDept.id,
level: 1,
description: 'Chief Executive - Full Access',
},
});
const salesManagerPosition = await prisma.position.create({
data: {
title: 'Sales Manager',
titleAr: 'مدير المبيعات',
code: 'SALES_MGR',
departmentId: salesDept.id,
level: 2,
description: 'Sales Department Manager',
},
});
const salesRepPosition = await prisma.position.create({
data: {
title: 'Sales Representative',
titleAr: 'مندوب مبيعات',
code: 'SALES_REP',
departmentId: salesDept.id,
level: 3,
description: 'Sales Representative',
},
});
console.log('✅ Created positions');
// Create Permissions for GM (Full Access)
const modules = ['contacts', 'crm', 'inventory', 'projects', 'hr', 'marketing'];
const resources = ['*'];
const actions = ['*'];
for (const module of modules) {
await prisma.positionPermission.create({
data: {
positionId: gmPosition.id,
module,
resource: resources[0],
actions,
},
});
}
// Create Permissions for Sales Manager
await prisma.positionPermission.createMany({
data: [
{
positionId: salesManagerPosition.id,
module: 'contacts',
resource: 'contacts',
actions: ['create', 'read', 'update', 'merge'],
},
{
positionId: salesManagerPosition.id,
module: 'crm',
resource: 'deals',
actions: ['create', 'read', 'update', 'approve'],
},
{
positionId: salesManagerPosition.id,
module: 'crm',
resource: 'quotes',
actions: ['create', 'read', 'update', 'approve'],
},
],
});
// Create Permissions for Sales Rep
await prisma.positionPermission.createMany({
data: [
{
positionId: salesRepPosition.id,
module: 'contacts',
resource: 'contacts',
actions: ['create', 'read', 'update'],
},
{
positionId: salesRepPosition.id,
module: 'crm',
resource: 'deals',
actions: ['create', 'read', 'update'],
},
{
positionId: salesRepPosition.id,
module: 'crm',
resource: 'quotes',
actions: ['create', 'read'],
},
],
});
console.log('✅ Created permissions');
// Create Employees
const gmEmployee = await prisma.employee.create({
data: {
uniqueEmployeeId: 'EMP-2024-0001',
firstName: 'Ahmed',
lastName: 'Al-Mutairi',
firstNameAr: 'أحمد',
lastNameAr: 'المطيري',
email: 'gm@atmata.com',
mobile: '+966500000001',
dateOfBirth: new Date('1980-01-01'),
gender: 'MALE',
nationality: 'Saudi',
employmentType: 'Full-time',
contractType: 'Unlimited',
hireDate: new Date('2020-01-01'),
departmentId: salesDept.id,
positionId: gmPosition.id,
basicSalary: 50000,
status: 'ACTIVE',
},
});
const salesManagerEmployee = await prisma.employee.create({
data: {
uniqueEmployeeId: 'EMP-2024-0002',
firstName: 'Fatima',
lastName: 'Al-Zahrani',
firstNameAr: 'فاطمة',
lastNameAr: 'الزهراني',
email: 'sales.manager@atmata.com',
mobile: '+966500000002',
dateOfBirth: new Date('1985-05-15'),
gender: 'FEMALE',
nationality: 'Saudi',
employmentType: 'Full-time',
contractType: 'Unlimited',
hireDate: new Date('2021-06-01'),
departmentId: salesDept.id,
positionId: salesManagerPosition.id,
reportingToId: gmEmployee.id,
basicSalary: 25000,
status: 'ACTIVE',
},
});
const salesRepEmployee = await prisma.employee.create({
data: {
uniqueEmployeeId: 'EMP-2024-0003',
firstName: 'Mohammed',
lastName: 'Al-Qahtani',
firstNameAr: 'محمد',
lastNameAr: 'القحطاني',
email: 'sales.rep@atmata.com',
mobile: '+966500000003',
dateOfBirth: new Date('1992-08-20'),
gender: 'MALE',
nationality: 'Saudi',
employmentType: 'Full-time',
contractType: 'Fixed',
hireDate: new Date('2023-01-15'),
departmentId: salesDept.id,
positionId: salesRepPosition.id,
reportingToId: salesManagerEmployee.id,
basicSalary: 12000,
status: 'ACTIVE',
},
});
console.log('✅ Created employees');
// Create Users
const hashedPassword = await bcrypt.hash('Admin@123', 10);
const gmUser = await prisma.user.create({
data: {
email: 'gm@atmata.com',
username: 'admin',
password: hashedPassword,
employeeId: gmEmployee.id,
isActive: true,
},
});
const salesManagerUser = await prisma.user.create({
data: {
email: 'sales.manager@atmata.com',
username: 'salesmanager',
password: hashedPassword,
employeeId: salesManagerEmployee.id,
isActive: true,
},
});
const salesRepUser = await prisma.user.create({
data: {
email: 'sales.rep@atmata.com',
username: 'salesrep',
password: hashedPassword,
employeeId: salesRepEmployee.id,
isActive: true,
},
});
console.log('✅ Created users');
// Create Contact Categories
await prisma.contactCategory.createMany({
data: [
{ name: 'Customer', nameAr: 'عميل', description: 'Paying customers' },
{ name: 'Supplier', nameAr: 'مورد', description: 'Product/Service suppliers' },
{ name: 'Partner', nameAr: 'شريك', description: 'Business partners' },
{ name: 'Lead', nameAr: 'عميل محتمل', description: 'Potential customers' },
],
});
console.log('✅ Created contact categories');
// Create Product Categories
await prisma.productCategory.createMany({
data: [
{ name: 'Electronics', nameAr: 'إلكترونيات', code: 'ELEC' },
{ name: 'Software', nameAr: 'برمجيات', code: 'SOFT' },
{ name: 'Services', nameAr: 'خدمات', code: 'SERV' },
],
});
console.log('✅ Created product categories');
// Create Pipelines
await prisma.pipeline.create({
data: {
name: 'B2B Sales Pipeline',
nameAr: 'مسار مبيعات الشركات',
structure: 'B2B',
stages: [
{ name: 'OPEN', nameAr: 'مفتوحة', order: 1 },
{ name: 'QUALIFIED', nameAr: 'مؤهلة', order: 2 },
{ name: 'NEGOTIATION', nameAr: 'تفاوض', order: 3 },
{ name: 'PROPOSAL', nameAr: 'عرض سعر', order: 4 },
{ name: 'WON', nameAr: 'فازت', order: 5 },
{ name: 'LOST', nameAr: 'خسرت', order: 6 },
],
isActive: true,
},
});
await prisma.pipeline.create({
data: {
name: 'B2C Sales Pipeline',
nameAr: 'مسار مبيعات الأفراد',
structure: 'B2C',
stages: [
{ name: 'LEAD', nameAr: 'عميل محتمل', order: 1 },
{ name: 'CONTACTED', nameAr: 'تم التواصل', order: 2 },
{ name: 'QUALIFIED', nameAr: 'مؤهل', order: 3 },
{ name: 'WON', nameAr: 'بيع', order: 4 },
{ name: 'LOST', nameAr: 'خسارة', order: 5 },
],
isActive: true,
},
});
console.log('✅ Created pipelines');
// Create sample warehouse
await prisma.warehouse.create({
data: {
code: 'WH-MAIN',
name: 'Main Warehouse',
nameAr: 'المستودع الرئيسي',
type: 'MAIN',
city: 'Riyadh',
country: 'Saudi Arabia',
isActive: true,
},
});
console.log('✅ Created warehouse');
console.log('\n🎉 Database seeding completed successfully!\n');
console.log('📋 Default Users Created:');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('1. General Manager');
console.log(' Email: gm@atmata.com');
console.log(' Password: Admin@123');
console.log(' Access: Full System Access');
console.log('');
console.log('2. Sales Manager');
console.log(' Email: sales.manager@atmata.com');
console.log(' Password: Admin@123');
console.log(' Access: Contacts, CRM with approvals');
console.log('');
console.log('3. Sales Representative');
console.log(' Email: sales.rep@atmata.com');
console.log(' Password: Admin@123');
console.log(' Access: Basic Contacts and CRM');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
}
main()
.catch((e) => {
console.error('❌ Error seeding database:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});