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

View File

@@ -0,0 +1,157 @@
import { Router } from 'express';
import { body, param } from 'express-validator';
import { dealsController, quotesController } from './crm.controller';
import { authenticate, authorize } from '../../shared/middleware/auth';
import { validate } from '../../shared/middleware/validation';
const router = Router();
// All routes require authentication
router.use(authenticate);
// ============= DEALS =============
// Get all deals
router.get(
'/deals',
authorize('crm', 'deals', 'read'),
dealsController.findAll
);
// Get deal by ID
router.get(
'/deals/:id',
authorize('crm', 'deals', 'read'),
param('id').isUUID(),
validate,
dealsController.findById
);
// Get deal history
router.get(
'/deals/:id/history',
authorize('crm', 'deals', 'read'),
param('id').isUUID(),
validate,
dealsController.getHistory
);
// Create deal
router.post(
'/deals',
authorize('crm', 'deals', 'create'),
[
body('name').notEmpty().trim(),
body('contactId').isUUID(),
body('structure').isIn(['B2B', 'B2C', 'B2G', 'PARTNERSHIP']),
body('pipelineId').isUUID(),
body('stage').notEmpty(),
body('estimatedValue').isNumeric(),
validate,
],
dealsController.create
);
// Update deal
router.put(
'/deals/:id',
authorize('crm', 'deals', 'update'),
param('id').isUUID(),
validate,
dealsController.update
);
// Update deal stage
router.patch(
'/deals/:id/stage',
authorize('crm', 'deals', 'update'),
[
param('id').isUUID(),
body('stage').notEmpty(),
validate,
],
dealsController.updateStage
);
// Mark deal as won
router.post(
'/deals/:id/win',
authorize('crm', 'deals', 'update'),
[
param('id').isUUID(),
body('actualValue').isNumeric(),
body('wonReason').notEmpty(),
validate,
],
dealsController.win
);
// Mark deal as lost
router.post(
'/deals/:id/lose',
authorize('crm', 'deals', 'update'),
[
param('id').isUUID(),
body('lostReason').notEmpty(),
validate,
],
dealsController.lose
);
// ============= QUOTES =============
// Get quotes for a deal
router.get(
'/deals/:dealId/quotes',
authorize('crm', 'quotes', 'read'),
param('dealId').isUUID(),
validate,
quotesController.findByDeal
);
// Get quote by ID
router.get(
'/quotes/:id',
authorize('crm', 'quotes', 'read'),
param('id').isUUID(),
validate,
quotesController.findById
);
// Create quote
router.post(
'/quotes',
authorize('crm', 'quotes', 'create'),
[
body('dealId').isUUID(),
body('items').isArray(),
body('subtotal').isNumeric(),
body('taxRate').isNumeric(),
body('taxAmount').isNumeric(),
body('total').isNumeric(),
body('validUntil').isISO8601(),
validate,
],
quotesController.create
);
// Approve quote
router.post(
'/quotes/:id/approve',
authorize('crm', 'quotes', 'approve'),
param('id').isUUID(),
validate,
quotesController.approve
);
// Send quote
router.post(
'/quotes/:id/send',
authorize('crm', 'quotes', 'update'),
param('id').isUUID(),
validate,
quotesController.send
);
export default router;