Skip to content

Module Overview — KPI Lifecycle And Notification

1. KPI module thực tế đang bị chia thành 4 lớp

LớpThành phầnVai trò
KPI core definitionkpi, kpi_participant, kpi_metric_relation, kpi_templateĐịnh nghĩa KPI, đối tượng, metric, target
KPI revenue surfacekpi_branch, kpi_staff, KPIRevenue*Dashboard và target doanh thu branch/staff
Progress runtimekpi_metric_relation_log, kpi_stats, kpi_metric_stats, AddKpiLogGhi nhận tiến độ thực tế và projection thống kê
Notification runtimekpi_branch_*, kpi_staff_*, kpi_notification, kpi_hotlineGửi assign/change/delete/remind/tổng hợp notifications

Điểm quan trọng là 4 lớp này dùng chung tên "KPI" nhưng không chạy trên cùng một engine duy nhất.

2. Surface map

FE routes

Route familyVai trò
/k/KPIsEntry module, hiện render KPIRevenue thay vì list KPI generic
/k/KPIs/createTạo KPI definition
/k/KPIs/:id/editCập nhật KPI definition
/k/KPIs/:id/*Detail KPI, tabs metric/target/my-kpi/branch-kpi
/k/KPIs/revenue/*Tạo/sửa KPI target doanh thu branch/staff

Backend runtime

RuntimeVai trò
Hasura CRUD trên kpi* tablesCreate/update/cancel/delete KPI core và branch/staff targets
Event kpi_branch_*, kpi_staff_*Gửi notification khi target được assign/change/delete
Scheduler kpi_notificationGửi staff remind, branch day/month aggregate, branch remind
Scheduler kpi_hotlineGhi KPI logs từ call center completed calls
AddKpiLogAPI nội bộ để các domain events ghi log KPI vào runtime layer

3. Lifecycle của KPI core là computed lifecycle

text
Create KPI
  -> insert kpi + participants + metric relations
  -> status FE = new | inprogress | closed (computed)

Update KPI
  -> update header
  -> sync participant delta
  -> sync metric relation delta
  -> vẫn không có status transition action riêng

Cancel KPI
  -> update_kpi_by_pk(_set: { canceled_at: now })
  -> status FE = canceled

Delete KPI
  -> update_kpi_by_pk(_set: { disabled: true })
  -> biến mất khỏi list nếu builder dùng disabled=false

Computed status ở FE

StatusCách suy ra
newfrom còn ở tương lai
inprogressfrom <= now <= tocanceled_at IS NULL
closedto < nowcanceled_at IS NULL
canceledcanceled_at IS NOT NULL
doneChỉ là display status phụ khi progress >= 100% trong vài component

Không có cột status canonical trong bảng kpi.

4. Progress runtime không nằm ở header

Nguồn dữ liệu chính

SurfaceVai trò
kpi_metric_relation_logEvent log của từng metric relation/participant
kpi_statsProjection tổng cho KPI
kpi_metric_statsProjection tổng cho từng metric relation
search_kpi_branch_*, search_kpi_staff_*Read models cho doanh thu KPI

Hai nhánh update

NhánhCách hoạt động
Manual metricFE gọi upsertManualMetrics để insert/update kpi_metric_relation_log
Auto metricEvent/scheduler backend gọi AddKpiLog(metricType, refIDs, extra)

Điều này có nghĩa "cập nhật KPI" và "cập nhật tiến độ KPI" là hai chuyện khác nhau về mặt runtime.

5. Notification model tổng quát

Event-trigger notifications

TriggerÝ nghĩa
kpi_branch_insertBranch target được assign lần đầu
kpi_branch_updateBranch target assign lần đầu hoặc thay đổi target
kpi_branch_deleteBranch target bị xóa
kpi_staff_insertStaff target được assign lần đầu
kpi_staff_updateStaff target assign lần đầu hoặc thay đổi target
kpi_staff_deleteStaff target bị xóa

Scheduler notifications

SchedulerLịch chạy metadataVai trò
kpi_notification0 14 * * *staff remind + branch day + branch month + branch remind
kpi_hotline0 16 * * *ghi KPI logs hotline từ CRM runtime

6. Findings nổi bật

IDFinding
MO-F01Entry route /k/KPIs render KPIRevenue, nên "module KPI" ở UI thực tế nghiêng về revenue dashboard trước khi vào KPI core.
MO-F02KPI lifecycle là computed lifecycle, nên mọi bug ở from/to/canceled_at sẽ đổi luôn status mà không có audit transition riêng.
MO-F03KPI_STATUS_DONE tồn tại nhưng không nằm trong KPI_STATUSES; enum status hiện không hoàn toàn đồng bộ.
MO-F04Notification boundary bị phân mảnh: event triggers, schedulers, kpi_permission, và upstream domain events đều tham gia.