Đặc tả Công thức Phân tích (ANALYTICS.md)
Tài liệu này là Nguồn tham khảo duy nhất (Source of Truth) cho toàn bộ logic tính toán trong hệ thống Plane Analytics.
⚠️ QUAN TRỌNG:
Mọi thay đổi logic trong code (src/lib/analytics.ts) phải được cập nhật vào file này trước. Nếu có sự sai khác, tài liệu này được coi là đúng.
📑 Mục lục
- Phạm vi dữ liệu
- Định nghĩa khái niệm cơ bản
- Effective Deadline — Hạn chót hiệu lực
- Priority Weight — Trọng số ưu tiên
- Velocity — Tốc độ sản lượng
- Reliability — Tính Cam kết
- Quality — Chất lượng công việc
- Complexity — Độ khó trung bình
- Consistency — Sự ổn định
- Overall Score — Điểm tổng thể
- Bottleneck Risk — Rủi ro điểm nghẽn
- Team Normalization — Chuẩn hóa đội ngũ
- Edge Cases — Các trường hợp đặc biệt
- Nhật ký thay đổi (Changelog)
1. Phạm vi dữ liệu
Dữ liệu được tính toán dựa trên một trong hai phạm vi sau:
| Phạm vi | Điều kiện lọc dữ liệu |
|---|---|
| Toàn dự án | issue.projectId = projectId |
| Theo Cycle | issue.projectId = projectId AND (cycleId = X OR dueDate IN range OR startedAt IN range OR createdAt IN range) |
Chiến lược lọc theo Cycle (Multi-Signal Strategy):
Để đảm bảo dữ liệu hiển thị đúng khi Dev không gándue_date, hệ thống kiểm tra 4 tín hiệu theo thứ tự:
- Exact match (
issue.cycle_id = X) — data import qua API mới (chính xác nhất).- due_date in window (
issue.due_date BETWEEN cycle.start AND cycle.end) — Dev set explicit deadline trong cycle.- started_at in window (
issue.started_at BETWEEN cycle.start AND cycle.end) — Dev bấm "Start" task trong cycle.- created_at in window (
issue.created_at BETWEEN cycle.start AND cycle.end) — Task được tạo trong cycle (lưới rộng nhất).Kết quả chẩn đoán thực tế (2026-04-23): 100% issue có
cycle_id = NULLvàdue_date = NULL.
→ Signal 3 (started_at) và 4 (created_at) là primary sources cho toàn bộ dữ liệu hiện tại.
Lưu ý: Nếu người dùng không chọn Cycle, hệ thống tính toán trên toàn bộ dự án.
2. Định nghĩa các khái niệm cơ bản
Công việc (Issue)
Mỗi Issue từ Plane chứa các trường dữ liệu quan trọng sau:
| Trường dữ liệu | Nguồn gốc | Ý nghĩa tính toán |
|---|---|---|
state_detail.group | Plane API | Nhóm trạng thái: completed, started, unstarted, backlog, cancelled |
isCompleted | Logic | true nếu nhóm trạng thái là completed |
displayId | API Importer | ID hiển thị dạng META-42 (identifier + sequence_id). Null với data cũ trước v1.3. |
cycleId | API Importer | DB UUID của cycle. Null với data import qua JSON/CSV cũ — fallback dùng due_date. |
completedAt | completed_at | Thời điểm hoàn thành thực tế |
dueDate | due_date | Hạn chót được gán riêng cho Issue |
cycleId | cycle.id | Cycle mà Issue thuộc về |
storyPoints | estimate_point | Điểm nỗ lực ước tính |
priorityWeight | Logic | Trọng số dựa trên mức độ ưu tiên |
Thành viên (Member)
Đối tượng được đánh giá. Metrics được tính toán riêng biệt cho từng thành viên trong một dự án cụ thể.
2.2. Chiến lược Estimate (Dành cho Dev)
Để báo cáo điểm nghẽn và tải công việc (Workload) chính xác nhất, team nên tuân thủ quy tắc estimate sau:
- Ưu tiên estimate ở Task con: Chia nhỏ công việc và gắn số giờ (1-16h) vào từng task con.
- Task cha để trống estimate: Task cha chỉ đóng vai trò gom nhóm công việc. Nếu gắn estimate ở cả cha lẫn con, hệ thống sẽ tính lặp thời gian (Ví dụ: Cha 10h, 2 con mỗi con 5h -> Hệ thống tính tổng là 20h), dẫn đến cảnh báo quá tải ảo cho nhân viên.
- Xác định Deadline: Nếu task không có
due_date, hệ thống sẽ tự tính deadline dựa trên:Ngày bắt đầu + số giờ estimate.
3. Effective Deadline
Hệ thống sử dụng Hạn chót hiệu lực để đảm bảo tính công bằng khi không phải mọi Issue đều có due_date.
// Thứ tự ưu tiên xác định hạn chót
effectiveDeadline(issue):
1. issue.dueDate // 1. Hạn chặt riêng (explicit)
2. start_date + story_points hours // 2. Tính từ ngày bắt đầu + estimate
3. cycle.endDate // 3. Hạn chặt cuối cùng là ngày kết thúc cycle
4. null // 4. Không có thông tin, bỏ qua metrics
Quy đổi Estimate → Hạn chặt (3-Tier)
| Tier | Điều kiện | Công thức |
|---|---|---|
| 1. Explicit | due_date có giá trị | Dùng trực tiếp |
| 2. Estimate | start_date + story_points (giờ) | addBusinessHours(start, hours) |
| 3. Cycle | Không có 1 & 2 | cycle.end_date |
Quy tắc Ngày làm việc: 8 giờ/ngày, Thứ 2 – Thứ 6.
Ví dụ:start_date = Thứ Hai 9:00,estimate = 16h→effectiveDeadline = Thứ Tư 17:00
SQL sử dụng lịch dương (calendar time) để phát hiện; TypeScript tính chính xác ngày làm việc cho hiển thị.
4. Priority Weight
Trọng số ưu tiên được gán cố định để tính toán độ khó và sản lượng:
| Priority | Trọng số (Weight) |
|---|---|
urgent | 4 |
high | 3 |
medium | 2 |
low | 1 |
none | 0 |
5. Velocity (Tốc độ sản lượng)
Đo lường tổng sản lượng của thành viên, có tính đến độ khó và điểm nỗ lực.
Bước 1: Tính Raw Velocity
rawVelocity = priorityWeightedCompleted + completedStoryPoints
priorityWeightedCompleted: Tổng trọng số ưu tiên của các Issue đã xong.completedStoryPoints: Tổng Story Points của các Issue đã xong.
Bước 2: Chuẩn hóa theo Team
velocityScore(member) = round( rawVelocity(member) / max(rawVelocity_trong_team) * 100 )
6. Reliability (Tính Cam kết)
Đo lường khả năng hoàn thành công việc đúng hạn.
reliabilityScore = (Số Issue đúng hạn / Tổng số Issue có hạn chót) * 100
Quy tắc đặc biệt:
- Nếu có Issue hoàn thành nhưng không có data deadline: Gán 50 (Trung tính).
- Nếu không hoàn thành Issue nào: Gán 0.
7. Quality (Chất lượng công việc)
Đánh giá dựa trên các lỗi phát sinh như trễ hạn hoặc bị mở lại.
penalties = số_issue_trễ + số_issue_mở_lại
qualityScore = max(0, 100 - (penalties / tổng_số_issue) * 100)
8. Complexity (Độ khó trung bình)
Đánh giá khả năng đảm nhận các tác vụ phức tạp.
avgPriority = Σ(priorityWeight) / số_issue_xong
complexityScore = round( min(100, avgPriority / 4 * 100) )
9. Consistency (Sự ổn định)
Đo lường sự biến động hiệu suất giữa các Cycle bằng hệ số biến thiên (CV).
consistencyScore = max(0, (1 - min(CV, 1)) * 100)
- CV = 0: Tuyệt đối ổn định (Score 100).
- CV ≥ 1: Biến động cực lớn (Score 0).
- Ít hơn 2 Cycles: Gán 70 (Trung tính - Tích cực).
10. Overall Score (Điểm tổng thể)
Là trung bình cộng của 5 chỉ số trên:
| Điểm số | Phân loại |
|---|---|
| ≥ 80 | 🌟 Xuất sắc |
| 65 – 79 | ✅ Tốt |
| 50 – 64 | 📊 Trung bình |
| < 50 | ⚠️ Cần cải thiện |
11. Bottleneck Risk (Rủi ro điểm nghẽn)
Phát hiện các thành viên đang có nguy cơ gây tắc nghẽn dòng công việc.
Phạm vi dữ liệu
Bottleneck sử dụng cùng chiến lược lọc dual-strategy như phần Phạm vi dữ liệu. Đặc biệt:
- Tất cả dữ liệu: Toàn bộ issue chưa hoàn thành được xét.
- Theo Cycle: Chỉ xét issue có
cycle_id = X(mới) hoặcdue_datetrong khoảng cycle (cũ). Điều này đảm bảo bottleneck không bao giờ trả về 0 kết quả chỉ vì data chưa có cycle link.
Ngưỡng rủi ro
| Risk Level | Điều kiện kích hoạt |
|---|---|
| 🔴 High | Quá hạn ≥ 3 HOẶC Đang làm ≥ 5 HOẶC (Đình trệ ≥ 2 và đang ở mức Medium) |
| 🟡 Medium | Quá hạn ≥ 1 HOẶC Đang làm ≥ 3 HOẶC Đình trệ ≥ 1 |
| 🟢 Low | Các trường hợp còn lại |
Định nghĩa
- Đang làm (In Progress):
isCompleted = false AND state NOT IN ('backlog','todo','cancelled','done')— bao gồm state tùy chỉnh nhưreview_on_prod,waiting_for_review. - Quá hạn (Overdue):
isCompleted = false AND effectiveDeadline < NOW()(dùng 3-tier effective deadline). - Blocked:
state = 'backlog' AND effectiveDeadline < NOW(). - Đình trệ (Stale):
isCompleted = false AND state ∈ active AND updated_at < NOW() - 3 ngày. Công việc đang làm nhưng không có hoạt động nào trong 3+ ngày liên tiếp.
12. Team Normalization
| Chỉ số | Chuẩn hóa? | Phương thức |
|---|---|---|
| Velocity | ✅ Có | So sánh với người cao nhất team |
| Reliability | ❌ Không | Chỉ số tuyệt đối |
| Quality | ❌ Không | Chỉ số tuyệt đối |
| Complexity | ❌ Không | Chỉ số tuyệt đối |
| Consistency | ❌ Không | Chỉ số tuyệt đối |
13. Edge Cases
| Tình huống | Cách xử lý |
|---|---|
| Không có Issue | Trả về null, bỏ qua thành viên |
| Không có Deadline | Reliability = 50 |
| Team 1 người | Velocity = 100 |
| Mới tham gia (<2 cycles) | Consistency = 70 |
14. Changelog
| Phiên bản | Ngày | Nội dung thay đổi |
|---|---|---|
| v1.0 | 2026-04-18 | Khởi tạo tài liệu với 5 công thức gốc. |
| v1.1 | 2026-04-18 | Bổ sung effectiveDeadline và xử lý trung tính Reliability. |
| v1.2 | 2026-04-22 | Chuẩn hóa cấu trúc tài liệu cho hệ thống Render mới. |
| v1.3 | 2026-04-23 | Bottleneck Cycle Filter: Thêm dual-strategy (exact cycle_id + date range fallback) cho filter theo cycle. Fix bug: chọn cycle cụ thể không hiển thị điểm nghẽn. Thêm displayId (META-42) vào data model. Fix label extraction cho cả CSV và API format. |
| v1.4 | 2026-04-23 | 3-Tier Effective Deadline: due_date › start_date + estimate (8h/ngày, Th2–T6) › cycle.end_date. Stale Detection: phát hiện task đang làm nhưng không hoạt động 3+ ngày. Risk scoring cập nhật tính đến staleCount. |
| v1.4.1 | 2026-04-23 | Multi-Signal Cycle Filter: Mở rộng cycle fallback từ 2 lên 4 tín hiệu (cycle_id → due_date → started_at → created_at). Fix root cause: 100% issue trong DB không có cycle_id và due_date, chỉ nhận diện được qua started_at/created_at trong khoảng thời gian cycle. |
| v1.5.0 | 2026-04-23 | UI & Accuracy Optimization: Hiển thị ID dạng META-xxx. Hiển thị tên trạng thái gốc từ Plane API. Hỗ trợ hiển thị Multi-Assignee. Fix lỗi lệch dữ liệu (mismatch) khi load trang/chuyển member. Bổ sung hướng dẫn estimate task cha/con. |
Duy trì bởi team anhphantools. Cập nhật lần cuối: 23/04/2026