Skip to content

Decision Brief — Tab Chu kỳ khách ghé không mua

Version: 2.7 Date: 05/05/2026 Profile: M Canonical Inputs: SOURCE_OF_TRUTH.md, EVIDENCE_PACK.md, prd.md, ui-spec.md, dev-spec.md, qa-test-plan.md, handoff.md.

Đây là cửa vào 5 phút cho PO/TL/Sếp. Đọc file này để nắm scope và quyết định; đọc các file execution khi cần giao việc chi tiết.

1) Tóm tắt quyết định

Bổ sung tab Chu kỳ khách ghé không mua trong report group Chu kỳ khách hàng để Marketing/CSKH nhìn thấy nhóm khách đã ghé chi nhánh nhưng không phát sinh doanh số và chưa chuyển đổi sau lượt ghé qualified gần nhất. Feature không sửa tab Chu kỳ mua hàng; tab mới dùng nguồn all_customer_visits với is_zero_order=truevisit_source thuộc consultant / do_service, kèm exclude rule DEC-014 cho khách đã chuyển đổi.

Phase 1 reuse shell filter/matrix/popup hiện có để giảm effort, nhưng không reuse wording hoặc output purchase-oriented. Popup mới hiển thị 1 khách/row để đội chăm sóc gọi lại — popup KHÔNG chứa khách đã chuyển đổi.

2) Package map

FileNgười đọcNội dung chính
prd.mdPO/BA, TLScope, FR/AC, formula nghiệp vụ
ui-spec.mdUI/FE/QAAs-is inventory, delta contract, wireframe, copy
dev-spec.mdBE/FE/TLAction/query/output contract, formulas implementation
qa-test-plan.mdQA/POTest oracle, cases, seed data
handoff.mdDelivery teamRACI, timeline, task order, blockers

Internal artifacts như EVIDENCE_PACK.md, SOURCE_OF_TRUTH.md, _consistency-matrix.md được giữ trong diva-group để audit nguồn, không publish vào sidebar dva-doc.

3) Scope lock

Trong phase 1Ngoài phase 1
Tab thứ 4 trong /r/reports/customer_cycle_report_groupExport Excel
Reuse filter Loại chu kỳ, Bước chu kỳ, Thời gian, Chi nhánhFilter nguồn visit cho user tự chọn
Hidden rules is_zero_order=true, source consultant/do_serviceChurn score hoặc card cảnh báo riêng
3 card/2 donut visit-basedCompare với tab Chu kỳ mua hàng
Matrix Chu kỳ khách ghéTự động tạo campaign chăm sóc
Popup detail 1 khách/row, search tên/SĐTField doanh thu/financial trong popup

4) Quyết định có ảnh hưởng triển khai

IDQuyết địnhTác động
DEC-003Khách ghé không mua bám is_zero_order=trueBE action dùng all_customer_visits, không suy từ order.total
DEC-005Row KH chưa quay lại ghé thay row Số khách có khả năng rời bỏUI/QA phải check copy và matrix order
DEC-006by_month = duration * 30 ngàyTest month boundary không dùng tháng lịch
DEC-007Popup 1 khách/row, branch theo latest qualified visitDetail action phải aggregate theo customer
DEC-010Action/query mới riêngKhông sửa reportPurchaseCycle/reportPurchaseCycleDetail
DEC-012Không data là empty payload, không errorFE hiển thị empty state, không toast lỗi
DEC-014Loại khách đã chuyển đổi sau ghéBE action thêm CTE converted_customers (EXCEPT) trước khi tính bucket; QA seed CUST-F/G/H/I
DEC-015Fix kèm bug tab persistence + to mappingFE phải sửa CustomerCycleReport.tsx:37 và whitelist getSavedTab() trong cùng PR; QA TC-001 cover regression tab Chu kỳ khách hàng
DEC-016BE enforce branch scope độc lập với FEBE thêm helper resolveBranchScope(ctx, requested) query user.branches; nếu user.branches rỗng = no branch restriction, nếu non-empty = intersect với requested; intersection rỗng mới trả empty payload; KHÔNG dùng Actor.IsAdmin(); QA TC-012 attempt bypass
DEC-017Loại ghé multi-source format cố địnhBE normalize visit_source theo thứ tự consultant → do_service; FE utility formatVisitSource join +; QA TC-013
v2.3/v2.7 (terminology)Rename T1-T5 + giữ tooltip reference trong UI B9FE implement core tooltip set cho phase 1; tooltip mở rộng vẫn giữ làm optional/backlog, không block GA; QA TC-014 verify copy + core tooltip
DEC-018Bucket by_month label sạch cho tab mớiDev C3 implement buildBuckets riêng (KHÔNG reuse purchase); QA TC-007 verify labels
DEC-019Cell value 0 → disable clickFE conditional click handler theo value; QA TC-015
DEC-020Performance NFR + benchmark gate + SQL fallbackBE benchmark trước GA; nếu fail → switch sang PostgreSQL function với window/CTE; block GA nếu không pass; QA TC-016
DEC-021Popup title {Row} • {Column}Component popup nhận rowLabel + columnLabel riêng (không build sẵn); QA TC-005 verify
DEC-022Tab label responsive ≥768px/<768pxFE dùng $q.screen.lt.md chọn i18n key full/short; tab key + URL không đổi; QA TC-017
DEC-023Date range max 365 ngày + clamp + toastFE clamp onChange; BE validate defense in depth (invalid_date_range); QA TC-018
DEC-024Bước chu kỳ [1,180]/[1,12] validationFE inline error theo type_cycle; BE validate (invalid_duration); QA TC-018
DEC-026Detail action nhận branch_ids để khớp matrix bucketBE detail re-apply resolveBranchScope rồi filter qualified_visits; QA TC-019 cross-branch drift
Review fix C-01DEC-016 revision — KHÔNG dùng Actor.IsAdmin() (returns true cho RoleUser)Dev C8 verification matrix + threat model; QA TC-012 expanded RoleUser footgun scenario
Review fix C-02Order enum canonical order_canceled/prepaid_canceledUpdate toàn package; nếu dùng sai canceled → khách CUST-I bị wrongly excluded
Review fix M-01FORMULA-002+ filter target_customersPRD/Dev formulas update; tránh donut/matrix tính cả khách đã chuyển đổi

5) Impact

LayerImpact
FEThêm tab key/panel, component report visit, query GraphQL, matrix/popup copy
BEThêm 2 actions: aggregate và detail visit no purchase
MetadataThêm action input/output trong Hasura metadata
DBKhông tạo bảng mới; đọc all_customer_visits, ecommerce_user, branch, order
QARegression tab mua hàng và test source/no-revenue/empty/multi-branch

6) Rủi ro chính

RiskGuard
User hiểu nhầm là chu kỳ mua hàngRewrite toàn bộ title/row/copy sang visit-based + core tooltip cho thuật ngữ dễ hiểu sai
Regression tab cũAction/query/component mới riêng, không sửa contract cũ
Empty data bị coi là lỗiAction mới trả payload rỗng hợp lệ
Same-day cross-branch không deterministicPopup branch hiển thị Nhiều chi nhánh
Manager bypass branch scopeDEC-016 BE intersect; QA TC-012
Liệt khách đã chuyển đổi vào danh sách CSKHDEC-014 EXCEPT converted_customers; QA TC-010
Tab cũ rớt persistence sau refreshDEC-015 fix kèm; QA TC-001
Loại ghé thứ tự không đồng nhấtDEC-017 fixed order; QA TC-013
Bucket label by_month gây nhầmDEC-018 đổi convention sạch cho tab mới
Popup empty mở từ cell value=0DEC-019 disable click
Action timeout @ scale lớnDEC-020 benchmark gate + SQL fallback plan
Tab label overflow trên mobileDEC-022 responsive label
User chọn date range nhiều năm → matrix khó đọcDEC-023 max 365 ngày + clamp
User nhập bước chu kỳ extremeDEC-024 FE/BE validate range
Popup title inconsistent giữa tab cũ/mớiDEC-021 lock format {Row} • {Column} riêng cho tab mới
Export làm nở scope/dữ liệu nhạy cảmDefer export sang phase sau

7) Handoff pointer

Team triển khai nên đi theo thứ tự:

  1. BE tạo aggregate/detail actions và metadata.
  2. FE thêm tab + GraphQL queries + generated types.
  3. FE build report, matrix, popup từ shell hiện có.
  4. QA chạy regression tab cũ trước khi UAT tab mới.

Timeline/RACI chi tiết nằm trong handoff.md.