Skip to main content

Bản thiết kế Mini-CRM với MERN stack

Một Mini-CRM gọn nhẹ xây trên MERN stack (MongoDB, Express, React, Node.js): quản lý khách hàng tiềm năng (lead) tập trung, theo dõi pipeline bán hàng dạng Kanban và xem báo cáo cơ bản — thay cho spreadsheet và ghi chú rời rạc của cá nhân kinh doanh, doanh nghiệp nhỏ và startup.

Tổng quan​

Mục tiêuNgười dùng
Quản lý lead tập trungCá nhân kinh doanh tự do
Theo dõi tiến độ pipelineDoanh nghiệp nhỏ và siêu nhỏ
Nâng cao hiệu suất làm việcĐội bán hàng nhỏ
Báo cáo cơ bảnStartup giai đoạn đầu
Dễ dùng, không cần đào tạo

Giá trị: thay spreadsheet bằng một hệ thống tập trung, nhìn thấy cả quy trình bán hàng để không bỏ lỡ cơ hội, lưu lịch sử trao đổi với từng khách, và ra quyết định dựa trên số liệu — với chi phí thấp.

Pipeline bán hàng​

Mỗi lead đi qua các giai đoạn, hiển thị thành các cột Kanban; kéo thẻ sang cột khác để đổi giai đoạn.

Thẻ lead hiển thị tên, công ty và giá trị dự kiến; mở thẻ để xem chi tiết và lịch sử ghi chú.

Mô hình dữ liệu​

CollectionTrường chínhGhi chú
usersemail, passwordHash, roleMật khẩu băm bằng bcrypt hoặc Argon2
leadsname, company, value, stage, ownerIdstage là enum cố định; value lưu số nguyên (VNĐ), không dùng số thực
activitiesleadId, type (ghi chú, cuộc gọi, email), content, createdAtLịch sử tương tác với khách
stage_changesleadId, from, to, changedAtLưu mỗi lần đổi giai đoạn — đầu vào cho tỉ lệ chuyển đổi và thời gian chốt deal

Đánh index { ownerId: 1, stage: 1 } cho truy vấn Kanban.

API​

MethodEndpointMô tả
POST/api/auth/loginĐăng nhập, trả JWT
GET/api/leads?stage=&q=Danh sách lead của người dùng, lọc và tìm kiếm
POST/api/leadsTạo lead
PATCH/api/leads/:idSửa lead, đổi giai đoạn (ghi thêm stage_changes)
DELETE/api/leads/:idXóa lead
POST/api/leads/:id/activitiesThêm ghi chú
GET/api/reports/pipelineSố lượng và tổng giá trị theo giai đoạn
Kiểm tra quyền sở hữu

Mọi truy vấn theo :id phải lọc cả ownerId (Lead.findOne({ _id: id, ownerId: req.user.id })). Chỉ lọc theo _id thì người dùng đổi id trong URL là xem được lead của người khác (lỗi IDOR).

Luồng hoạt động​

Xác thực​

Lưu JWT trong cookie HttpOnly, Secure, SameSite thay vì localStorage để script độc hại không đọc được.

Tạo lead​

  1. Người dùng nhập thông tin lead trên form.
  2. Frontend gửi POST /api/leads (cookie đi kèm tự động).
  3. Backend xác thực token, validate dữ liệu, gán ownerId = req.user.id, lưu vào MongoDB.
  4. Frontend thêm lead mới vào cột "Mới" trên Kanban.

Dashboard báo cáo​

Số liệu cho biểu đồ pipeline lấy bằng một aggregation:

reports.controller.js
const pipeline = await Lead.aggregate([
{ $match: { ownerId: req.user._id } }, // hoặc cả đội, nếu là manager
{ $group: { _id: "$stage", count: { $sum: 1 }, totalValue: { $sum: "$value" } } },
]);

Từ stage_changes có thể tính thêm: tỉ lệ thắng, tỉ lệ chuyển đổi giữa các giai đoạn, thời gian trung bình để chốt deal.

Hướng phát triển​

Tính năngMô tả
Email & lịchGửi email, đặt lịch hẹn ngay trong CRM
Quản lý công việcTạo và giao task gắn với từng lead
Phân quyền chi tiếtVai trò Admin, Manager, Sales; manager xem lead của cả đội
Báo cáo nâng caoThêm bộ lọc theo thời gian, nhân viên và loại biểu đồ
Tự động hóaTự gửi email hoặc tạo task khi lead đổi giai đoạn
Docker & CI/CDĐóng gói và tự động triển khai — xem Thiết lập máy chủ Ubuntu