Skip to content

PRD: Tích điểm

ModuleKhách hàng thân thiết (EXT-01)PRD IDPRD-PTS-001
StatusPlannedOwnerLoyalty squad
Date2026-03-23Versionv0.1
Packages@nx/sale · @nx/coreURDPTS

TL;DR

Cho phép merchant tự động biến mỗi đơn đã thanh toán và gắn với khách hàng thành điểm thưởng - số dư của khách tăng ngay khi thanh toán hoàn tất, theo tỷ lệ quy đổi riêng cho từng merchant. Mỗi lần cộng được ghi nhận một lần cho mỗi đơn dưới dạng một point transaction kiểm toán được, nên khách quay lại thấy điểm tích lũy mà không cần nhập tay, còn merchant có một sổ điểm xác minh được.

1. Context & Problem

Module Khách hàng thân thiết biến các lần mua hoàn tất thành điểm để khách quay lại thường xuyên hơn. Trước khi có tích điểm, đơn đã thanh toán không để lại dấu vết loyalty nào: không có sổ điểm, không tích lũy số dư, và không có liên kết từ đơn tới điểm mà nó sinh ra. Khách không được thưởng cho chi tiêu, còn merchant không có nền tảng để xây dựng đổi điểm, hạng thành viên hay phần thưởng.

Tích điểm là phần đầu tiên (tính năng PTS, giai đoạn P1): một đơn gắn với khách hàng khi hoàn tất thanh toán sẽ tự động cộng điểm vào số dư của khách, một lần, theo tỷ lệ quy đổi riêng cho từng merchant. Nó xây dựng trên định danh khách hàng sẵn có (nơi giữ số dư) và luồng đơn hàng/thanh toán (nơi báo hiệu hoàn tất), và là điều kiện tiên quyết cho mọi năng lực loyalty sau này.

2. Goals & Non-Goals

Goals

  • Cộng điểm tự động khi một đơn gắn với khách hàng hoàn tất thanh toán, không cần nhập tay.
  • Làm cho lần cộng idempotent theo từng đơn để một payload thanh toán gửi lại hay trùng lặp không bao giờ cộng đôi.
  • Đọc tỷ lệ quy đổi từ cấu hình riêng cho từng merchant, dùng giá trị mặc định khi chưa đặt.
  • Ghi mỗi lần cộng dưới dạng một PointTransaction (loại EARN) và tăng số dư điểm của khách trong một thao tác duy nhất.
  • Cung cấp một API liệt kê point transaction chỉ đọc (find / findById / findOne / count), scope theo merchant.

Non-Goals

  • Đổi điểm, hạng thành viên và danh mục phần thưởng - thuộc tính năng RDM (giai đoạn P2, URD-RDM).
  • Quỹ điểm dùng chung / liên merchant (Non-Goal của URD).
  • Gửi tin nhắn marketing khi tích điểm (thuộc Marketing).
  • Cộng điểm cho đơn ẩn danh (ràng buộc C-01 - chỉ khách đã định danh mới tích lũy).

3. Success Metrics

MetricMục tiêu / tín hiệu
Độ phủ100% đơn đã thanh toán gắn với khách hàng đều cộng điểm (khi tỷ lệ dương)
IdempotencyKhông cộng đôi - nhiều nhất một transaction EARN cho mỗi đơn
Độ chính xácpointBalance bằng tổng các transaction EARN của khách
Độ trễViệc cộng hoàn tất trong luồng xác nhận thanh toán mà không làm chậm việc hoàn tất đơn

4. Personas & Use Cases

PersonaMục tiêu trong tính năng này
CustomerTự động tích điểm khi mua hàng và thấy số dư tăng lên
OwnerĐặt tỷ lệ tích và tin rằng mỗi đơn đã thanh toán đều tích lũy đúng
ManagerXem hoạt động điểm và số dư của thành viên

Core scenarios: một đơn gắn với khách hàng hoàn tất thanh toán → hệ thống đọc tỷ lệ quy đổi của merchant → tính điểm từ tổng đơn → ghi một transaction EARN và tăng số dư của khách, một lần cho mỗi đơn.

5. User Stories

  • Là một customer, tôi muốn điểm được cộng tự động vào số dư khi đơn được thanh toán, để được thưởng cho chi tiêu mà không cần làm gì.
  • Là một owner, tôi muốn tỷ lệ tích được cấu hình riêng cho từng merchant, để kiểm soát cách chi tiêu quy đổi thành điểm.
  • Là một owner, tôi muốn một payload thanh toán trùng lặp không bao giờ cộng đôi, để sổ điểm luôn đáng tin.
  • Là một manager, tôi muốn liệt kê các point transaction của một khách, để xem số dư của họ được tích lũy như thế nào.

6. Functional Requirements

#Yêu cầuURD ref
FR-1Cộng điểm khi một đơn gắn với khách hàng hoàn tất thanh toán; cùng một logic chạy trên cả hai đường hoàn tất thanh toán (order-payment và check-payment)URD-PTS-001
FR-2Việc tích là idempotent theo từng đơn - dừng sớm nếu đơn đã được cộng điểmURD-PTS-002
FR-3Tỷ lệ quy đổi đọc từ cấu hình riêng cho từng merchant (POINT_CONVERSION_RATE); dùng mặc định khi chưa đặtURD-PTS-003
FR-4points = floor(orderTotal / conversionRate); tỷ lệ không dương hoặc điểm bằng không thì bỏ qua (ghi log, không cộng)URD-PTS-001
FR-5Trong một transaction: chèn một PointTransaction (loại EARN, với points, conversionRate, saleOrderId) và tăng pointBalance của khách; roll back khi lỗiURD-PTS-001..002
FR-6API liệt kê point transaction chỉ đọc (find / findById / findOne / count), scope theo merchantURD-PTS-001

Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong URD Khách hàng thân thiết. PRD này tham chiếu chúng thay vì lặp lại.

7. Non-Functional Requirements

AreaYêu cầu
Data integrityLệnh chèn PointTransaction và việc tăng pointBalance được ghi trong một transaction - không thay đổi số dư mà thiếu một bản ghi sổ điểm tương ứng
IdempotencyNhiều nhất một lần cộng EARN cho mỗi đơn, đảm bảo bằng kiểm tra tồn tại trên saleOrderId
Tenancy & authzMọi thao tác scope theo merchant (x-merchant-id); API liệt kê được gác bởi permission của sale (JWT / Basic auth)
Độ chính xácTính toán tiền / điểm dùng float(value, 4); điểm được làm tròn xuống đơn vị nguyên
PerformanceViệc cộng chạy bên trong luồng xác nhận thanh toán mà không làm chậm việc hoàn tất đơn
i18nNhãn/trạng thái hướng người dùng là song ngữ ({ en, vi })

8. UX & Flows

Tích điểm không có UI riêng - nó chạy phía server khi thanh toán hoàn tất. Số dư đã tích hiện ra trong hồ sơ khách hàng (apps/client); point transaction truy cập được qua API liệt kê chỉ đọc.

9. Data & Domain

EntityVai trò
PointTransactionBản ghi sổ chỉ thêm - loại EARN, points, conversionRate, saleOrderId, scope theo merchant
Customer.pointBalanceSố dư đang chạy, được tăng trong một thao tác duy nhất cùng mỗi lần cộng
Configuration (POINT_CONVERSION_RATE)Dòng tỷ lệ riêng cho từng merchant (group SYSTEM, principal = merchant, status ACTIVATED); dùng mặc định khi vắng

Chỉ ở mức khái niệm - toàn bộ schema và bất biến nằm trong tài liệu customer-points lập trình viêndomain model của sale.

10. Dependencies & Assumptions

Phụ thuộc vào

  • Định danh khách hàng (Khách hàng) - giữ pointBalance mà lần cộng làm tăng.
  • Đơn hàng / thanh toán (Đơn hàng) - đơn hoàn tất trên đường thanh toán là điều kiện kích hoạt tích điểm.
  • Cấu hình riêng cho từng merchant (@nx/core) - cung cấp POINT_CONVERSION_RATE.

Giả định

  • Đơn được gắn với một khách hàng đã định danh (đơn ẩn danh không tích, C-01).
  • Có tỷ lệ quy đổi được cấu hình, hoặc áp dụng mặc định.
  • Các webhook hoàn tất thanh toán kích hoạt đáng tin cho mỗi đơn đã thanh toán.

11. Risks & Open Questions

Rủi ro / câu hỏiGiảm thiểu / trạng thái
Payload thanh toán trùng lặp / gửi lại có thể cộng đôiIdempotent theo từng đơn - kiểm tra tồn tại trên saleOrderId trước khi cộng (C-02)
Lần cộng và việc tăng số dư có thể lệch nhau khi lỗi một phầnCả hai ghi trong một transaction; roll back cùng nhau khi lỗi
Tỷ lệ cấu hình sai (không dương) có thể cộng giá trị rácTỷ lệ không dương hoặc điểm bằng không thì bỏ qua và ghi log, không bao giờ cộng
Hoàn tiền / hủy sau khi đã tíchMở: định nghĩa đường thu hồi / đảo điểm đã tích

12. Release Plan & Launch Criteria

AspectKế hoạch
PhaseP1 (nền tảng) - xem feature catalog của URD
RolloutTất cả merchant; không có feature flag
MigrationKhông (entity PointTransaction mới; tỷ lệ quy đổi lấy từ cấu hình)
Launch criteriaĐơn gắn khách hàng đã thanh toán cộng điểm một lần; số dư khớp sổ EARN; payload trùng lặp không cộng đôi; tỷ lệ đọc theo từng merchant
MonitoringLượng cộng điểm theo merchant, phát hiện cộng đôi (đơn có >1 EARN), kiểm tra nhất quán số dư so với sổ điểm

13. FAQ

Điểm được cộng vào lúc nào? Khi một đơn gắn với khách hàng hoàn tất thanh toán - cùng một logic chạy dù xác nhận đến qua đường order-payment hay check-payment.

Cùng một đơn có cộng điểm hai lần được không? Không - việc tích là idempotent theo từng đơn. Nếu đã tồn tại một transaction EARN cho đơn, lần cộng bị bỏ qua.

Tỷ lệ tích đến từ đâu? Từ cấu hình POINT_CONVERSION_RATE riêng cho từng merchant; áp dụng mặc định khi chưa đặt.

Điểm được tính như thế nào? points = floor(orderTotal / conversionRate). Tỷ lệ không dương hoặc kết quả bằng không thì bỏ qua (ghi log, không cộng).

Đơn ẩn danh có tích điểm không? Không - chỉ khách đã định danh mới tích lũy (ràng buộc C-01).

Đã đổi điểm được chưa? Chưa trong phần này. Đổi điểm, hạng thành viên và danh mục phần thưởng là tính năng RDM riêng (giai đoạn P2, URD-RDM).

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.