Tổng quan
ATAY Admin là web nội bộ quản lý 4 đội lắp đặt (Xe A Cường / Đạt / Vũ / Ông Nắt). Mục đích chính:
- Quản lý đơn hàng + khách hàng + lịch lắp đặt theo từng xe
- Giao việc cho thợ qua link công khai riêng từng xe (không cần login)
- Thợ báo cáo hoàn thành kèm ảnh/video từ điện thoại
- Sale/admin duyệt báo cáo trước khi đơn thật sự "hoàn thành"
- Báo cáo doanh thu theo xe / sale / marketing / sản phẩm
🎭 3 vai trò chính:
- Admin — login web, quản trị toàn bộ. Tạo đơn, duyệt báo cáo, xem doanh thu.
- Sale/Marketing — login web, xem đơn của họ, đánh dấu đã làm.
- Thợ (đội xe) — KHÔNG login, mở link riêng của xe trên điện thoại, xem lịch + báo cáo xong.
Quy trình 1 đơn từ A → Z
Sale/Admin nhận yêu cầu KH
│
▼
/orders → "Tạo đơn mới"
│
┌────────────┴────────────┐
▼ ▼
Pick khách cũ Tạo khách mới
└────────────┬────────────┘
▼
Sản phẩm + SL + diện tích báo giá
│
▼
Chọn ngày + giờ lắp
│
▼
┌─────────────────────────────────┐
│ 💡 Suggest tự chấm điểm 4 xe │ ← khoảng cách+load+VIP boost
│ reason hiển thị bên cạnh │
└──────────────┬──────────────────┘
│
▼
Pick 1-4 xe (vehicleCount)
Xe đầu tiên = xe chính (primary)
│
▼
Lưu đơn 💾
Status = "Đã chốt" 🟡
│
▼
Đến ngày lắp:
Thợ mở /share/<token> (link cố định)
│
▼
Đi làm → bấm "📷 Báo cáo xong"
Upload ảnh/video + (optional) doanh thu/diện tích thực
│
▼
Status = "Chờ duyệt" 🟣
Thợ thấy badge "Đang chờ admin duyệt"
│
▼
Admin /orders → click đơn → ApprovalBanner tím
Xem ảnh báo cáo → [Duyệt] hoặc [Trả lại]
│
┌────────────┴────────────┐
▼ ▼
Duyệt Trả lại + lý do
↓ ↓
Status = "Hoàn thành" ✅ Status = "Chưa lắp" 🟡
Doanh thu vào /reports Thợ phải báo lạiLink riêng cho từng xe
Mỗi xe có 1 URL công khai dạng joshinoibo.com/share/<uuid>. Thợ mở trên điện thoại, bookmark là dùng mãi — không cần login, không cần app.
📍 Lấy link ở đâu?
Vào /teams → mỗi card xe có ô "LINK CỐ ĐỊNH CHO THỢ" với 2 nút Copy + Mở.
🌐 Thợ xem được gì?
- 2 tab: Hôm nay + Ngày mai
- Mỗi đơn: giờ, tên KH, sản phẩm + SL, district, địa chỉ, ghi chú
- 2 nút lớn: 📞 Gọi · 🗺 Mở Google Maps
- Toggle TH ↔ VI góc trên phải
- KHÔNG thấy: báo giá, doanh thu, sale/marketing, đơn xe khác
🔐 An toàn
URL UUID 36 ký tự ngẫu nhiên — không đoán được. Link KHÔNG đổi theo ngày. Nếu rò rỉ: rotate bằng SQL update teams set share_token = gen_random_uuid() where code = 'XE_X'.
Đổi ngôn ngữ TH ↔ VI (trang share)
Trên trang share của thợ, góc phải header có toggle TH / VI. Click một lần lưu cookie 1 năm, thợ dùng mãi không phải chọn lại.
📝 Text đã dịch full
- Tab "Hôm nay / Ngày mai" ↔ "วันนี้ / พรุ่งนี้"
- Status badges: Chưa lắp / Chờ duyệt / Đã xong / Đổi lịch / …
- Format ngày: tiếng Việt (28/05/2026) vs Thái Phật lịch (28/05/2569)
- Nút "📞 Gọi" / "🗺 Mở bản đồ" / "📷 Báo cáo xong"
- Relative time "X phút trước" / "X นาทีที่แล้ว"
🔧 Mặc định
Lần đầu mở = Thai (vì thợ ATAY native Thai). Cookie tên share_lang lưu domain joshinoibo.com.
Thợ upload ảnh/video báo cáo
Sau khi làm xong, thợ click nút đen "📷 Báo cáo xong" trên card đơn → mở dialog full-screen:
🛡 Security
- Backend verify token + đơn thuộc xe trước khi accept upload
- Đơn 2+ xe: chỉ xe primary upload được
- File path =
<order_id>/<random-uuid>.<ext>
Duyệt báo cáo 2 bước
Sau khi thợ upload, đơn KHÔNG auto chuyển Hoàn thành — phải qua admin duyệt:
Thợ upload + Gửi → Status = Chờ duyệt 🟣
│
▼
Admin vào /orders → click đơn → dialog chi tiết
│
┌──────────────────────────────┴────────────────────────┐
│ Banner tím nổi bật trên cùng: │
│ "Thợ đã báo cáo — xem ảnh phía dưới rồi duyệt" │
│ │
│ [Duyệt → Hoàn thành] [Trả lại thợ] │
└──────────────┬─────────────────────────┬───────────────┘
▼ ▼
Status = Hoàn thành ✅ Status = Chưa lắp 🟡
Doanh thu vào /reports Append note "[Trả lại …]"⚠ Lưu ý
- Khi thợ đã báo cáo, nút "Báo cáo xong" trên share biến mất.
- Trả lại = prompt nhập lý do → append vào note với tag
[Trả lại YYYY-MM-DD HH:mm bởi admin@email] - Sau khi trả lại, thợ thấy nút "Báo cáo xong" hiện lại.
Đơn nhiều xe — rule xe chính
Đơn lớn cần 2-4 xe. Khi tạo đơn chọn vehicleCount=2, có thể pick 2 xe. Xe đầu tiên = xe chính (is_primary=true).
⚖ Rule báo cáo
| Loại đơn | Xe chính | Xe phụ |
|---|---|---|
| Đơn 1 xe | ✅ Báo cáo | — |
| Đơn 2+ xe | ✅ Báo cáo | ❌ "Xe chính báo cáo đơn này" |
Đặt đơn lớn (nhiều buổi/ngày)
Đơn lớn không xong trong 1 buổi (làm nhiều ngày, mỗi ngày có thể khác số xe, có ngày làm nửa ngày). Cả đơn lớn vẫn là 1 đơn duy nhất → doanh thu chỉ tính 1 lần, không bị cộng theo số ngày.
Cách làm: ngày đầu nhập như đơn thường (khách / sản phẩm / ngày / giờ / xe). Sau đó cuộn xuống khu Buổi làm thêm (đơn lớn nhiều ngày) và thêm các ngày kế tiếp.
🛠️ Các bước
Ví dụ đơn 3 ngày:
Buổi 1 (ngày 1): Xe A 08:00 · cả ngày
Buổi 2 (ngày 2): Xe A + Xe B 08:00 · cả ngày
Buổi 3 (ngày 3): Xe A 08:00 · nửa ngày (240')
→ chiều ngày 3 Xe A vẫn TRỐNG, nhận việc khác được.📌 Cần nhớ
- Xe bận theo từng buổi: xe đã nhận buổi nào thì khoá đúng ngày/giờ đó — không ai đặt trùng lên được. Ngày/giờ khác vẫn rảnh.
- Nửa ngày = nhả nửa còn lại: để thời lượng ngắn thì khoảng thời gian còn lại trong ngày của xe đó vẫn trống cho đơn khác.
- Trên Lịch lắp: mỗi buổi hiện 1 ô riêng đúng ngày của nó, gắn nhãn buổi. Ô buổi xem được nhưng không kéo-thả — muốn sửa thì mở đơn gốc ở
Đơn hàng. - Sửa/xoá: mở lại đơn → thêm/bớt buổi → Lưu. Xoá hết buổi thì đơn về lại đơn 1 ngày bình thường.
- Doanh thu: nhập ở phần chính của đơn, tính 1 lần dù nhiều buổi.
Đơn chỉ làm trong 1 ngày thì bỏ qua khu "Buổi làm thêm" — mọi thứ như cũ.
Gợi ý xe + VIP boost
Khi tạo đơn, panel bên phải fire suggest chấm điểm 4 xe (0-100):
🎯 Công thức điểm
điểm = proximity × 0.40 (khoảng cách tới đơn gần nhất)
+ load_balance × 0.25 (đơn còn chỗ, ≤5/ngày)
+ time_fit × 0.20 (không trùng giờ)
+ area_fit × 0.10 (district khớp default_area)
− overwork (−30 nếu > 8h/ngày)
+ vip_boost (+10 nếu KH VIP + xe có leader)📊 Tier
- best ≥ 70 điểm
- good 50-69
- ok 30-49
- avoid < 30 / nghỉ / trùng giờ
Kéo-thả đổi xe trên Schedule
Vào /schedule?view=day → Day Timeline 7h-20h với 4 cột xe.
⚠ Hạn chế
- Chỉ đổi xe, KHÔNG đổi giờ.
- Đơn nhiều xe → KHÔNG kéo được.
- Status đơn KHÔNG đổi.
Bản đồ + Tối ưu lộ trình (TSP)
/map?date=YYYY-MM-DD hiển thị tất cả đơn ngày đó trên bản đồ Bangkok, marker màu theo xe. Đường nét đứt = tuyến đề xuất.
🧭 Tối ưu lộ trình
Trong Day Timeline có nút "Tối ưu lộ trình":
- Liệt kê xe có ≥2 đơn trong ngày
- So sánh thứ tự hiện tại vs thứ tự TSP đề xuất
- Tổng km tiết kiệm
⚠ Chỉ là gợi ý — đổi thứ tự = đổi giờ KH → gọi xác nhận trước.
Báo cáo doanh thu + Excel
/reports — chọn khoảng ngày (Hôm nay / 7 ngày / Tháng / Năm).
📈 KPI hiển thị
- Tổng doanh thu thực (chỉ Hoàn thành) + báo giá
- Số đơn theo: hoàn thành / đổi lịch / huỷ / lưới / giàn
- Doanh thu từng xe + sale + marketing + sản phẩm
- Matrix Ngày × Xe
📥 Xuất Excel (7 sheet)
Nút "Xuất Excel" → tải ATAY-baocao-YYYY-MM-DD-YYYY-MM-DD.xlsx:
- Sheet 1: Chi tiết đơn (27 cột, freeze + auto-filter)
- Sheet 2: Tổng quan KPI
- Sheet 3-6: Theo xe / Sale / Marketing / Loại sản phẩm
- Sheet 7: Matrix Ngày × Xe
Cảnh báo Dashboard
Dashboard tự tính 3 nhóm cảnh báo (ẨN nếu không có):
- VIP chưa xếp xe — đơn KH VIP đang active mà chưa có assignment.
- Xe FULL ≥3 ngày liên tiếp trong 7 ngày tới.
- Đơn quá hạn — đơn scheduled_date < hôm nay mà vẫn active.
Lịch trống nhanh (QuickFit)
Nút ⚡ "Lịch trống nhanh"ở sidebar trên cùng. Use case: KH hỏi "lắp được ngày nào sớm nhất gần Khlong Toei?".
⚡ Flow:
- Mặc định: Hôm nay → 14 ngày tới
- Optional nhập district hoặc paste Google Maps link
- System list slots trống của 4 xe, sort theo ngày gần nhất
- Click 1 slot → mở form tạo đơn với prefill
Realtime tự refresh
Khi 1 admin tạo / sửa / xoá đơn (hoặc thợ submit qua share), các admin khác đang mở web tự cập nhật sau ~3 giây — không cần F5.
🔌 Cơ chế
Supabase Realtime push event postgres_changes cho orders + order_assignments. Client subscribe → router.refresh() throttle 3000ms.
Quản lý user (admin only)
/users chỉ admin xem được. Tạo tài khoản đăng nhập cho Sale / Marketing + bật/khoá / đổi role / reset password.
👤 4 roles
- Admin — toàn quyền
- Sale — CRUD orders + customers. KHÔNG xoá đơn.
- Marketing — gần giống Sale (default không duyệt báo cáo)
- Viewer — chỉ xem
➕ Tạo user mới
- Click "Thêm user"
- Nhập email + chọn role (password auto-gen)
- Click "Tạo user" → login ngay
- Copy mật khẩu gửi user qua Signal/SMS
Phân quyền role + per-user
Hệ thống 2 lớp — admin tự bật/tắt từng permission cho từng role, hoặc override per user.
Effective permission = thứ tự ưu tiên:
① USER override (user_permissions) ← cao nhất
② ROLE override (role_permissions)
③ DEFAULT (DEFAULT_ROLE_PERMS hard-code)
④ Critical lock — admin LUÔN có: ← bypass override
users.manage / users.permissions /
audit.view / settings.write🎛 Tab "Phân quyền theo role"
- 9 nhóm × 27 permissions × 4 cột role
- Click cell → toggle. Nếu = default → auto xoá override
- Chấm tím = đã override
- 🔒 = critical, không tắt được
Nhật ký hành động (audit log)
/audit (admin only) — log mọi mutation quan trọng: tạo/sửa/xoá đơn, đổi status, duyệt, kéo-thả, upload từ thợ, tạo/khoá user.
📋 Mỗi row
- Timestamp (đến giây)
- User email + role tại thời điểm action
- Action badge màu
- Target table + ID
- Payload JSON expandable
- IP
Chấm công (thợ + văn phòng)
Trang /attendance (menu Chấm công) — chấm công theo TỪNG NGƯỜI: thợ (nhóm theo xe) + nhân viên văn phòng. Chỉ admin + kế toán xem/sửa được (role khác ẩn menu).
🗓️ Cách chấm (bấm vào ô ngày của từng người)
- Ngày thường (T2–T7): mặc định coi như ĐI LÀM. Bấm ô → chọn Nghỉ cả ngày / Nghỉ nửa ngày + ghi chú (lý do).
- Chủ nhật: mặc định NGHỈ. Ai đi làm thì bấm ô → Tăng ca cả ngày / nửa ngày (đi làm CN = tăng ca).
- Ô đỏ N = nghỉ · ô xanh TC = tăng ca CN · ½ = nửa ngày · chấm vàng = có ghi chú (rê chuột xem).
📊 Báo cáo công tháng (dưới lưới)
- Mỗi người: Công thường + Công CN (tăng ca) + Ngày nghỉ + Tổng công.
- Công thường = số ngày T2–T7 trong tháng − số ngày nghỉ.
- Nút Xuất Excel (2 sheet: Tổng hợp mỗi người + Chi tiết từng ngày kèm ghi chú).
- ⚠ Đếm ĐỦ ngày T2–T7 của cả tháng → chạy cho tháng đã kết thúc mới khớp thực tế (tháng đang chạy sẽ tính luôn ngày chưa tới).
👷 Thợ trong xe + đội trưởng
- Vào
/teams→ thẻ mỗi xe có nút "Thêm thợ" (thêm nhanh: tên + biệt danh + SĐT), hoặc mục Nhân sự → vai trò Thợ + chọn Xe. - Chọn đội trưởng ngay trên thẻ xe (dropdown trong các thợ của xe đó).
- Thợ có thể được cấp tài khoản đăng nhập (quyền viewer) ở mục Nhân sự — tùy chọn, không bắt buộc.
- Thêm thợ vào xe xong → tự hiện trong Chấm công, xếp theo xe.
Cài đặt + nhân viên
👥 Quản lý xe + thợ + nhân viên
Vào /teams:
- Danh sách xe — sửa tên / khu vực / màu / link chia sẻ; chọn đội trưởng + Thêm thợ ngay trên thẻ xe
- Nhân sự — thợ + sale/marketing/kế toán; thêm/sửa + cấp tài khoản đăng nhập; thợ gắn 1 xe
- Lịch off theo xe — đánh dấu ngày xe nghỉ (dùng cho xếp lịch/chống trùng, KHÁC với Chấm công theo người)
🤖 Telegram bot
/settings → setup token + chat_id cho mỗi xe.