PRD: Tích điểm
| Module | Loyalty | PRD ID | PRD-PTS-001 |
| Trạng thái | Sẵn sàng dev | FEAT | PTS |
| Epic | — | Plane | BANA-1509 |
| Ngày | 2026-03-23 | Phiên bản | v0.1 |
| Gói | @nx/sale | URD | PTS |
| Surface | Backend | ||
| Phụ trách | Phát Nguyễn | ||
TL;DR
Mỗi đơn đã thanh toán và gắn với khách hàng tự động sinh điểm: số dư tăng ngay khi thanh toán xong, theo tỷ lệ quy đổi riêng từng merchant. Mỗi đơn chỉ cộng đúng một lần dưới dạng một mục sổ điểm kiểm toán được - không cần nhập tay, có dấu vết điểm xác minh được.
1. Context & Problem
Module Loyalty biến lần mua thành điểm để khách quay lại. Trước đây, đơn đã thanh toán không để lại dấu vết loyalty nào - không sổ điểm, không số dư, không liên kết giữa đơn và điểm đáng lẽ nó sinh ra. Khách chi tiêu mà chẳng được gì, còn merchant thì thiếu nền tảng để làm đổ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): đơn đã thanh toán gắn với khách hàng 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 từng merchant. Nó dựa trên định danh khách hàng (nơi giữ số dư) và luồng đơn/thanh toán (nơi báo hoàn tất), và là điều kiện tiên quyết cho mọi năng lực loyalty về sau.
2. Goals & Non-Goals
Goals
- Cộng điểm tự động cho đơn đã thanh toán gắn với khách hàng - không nhập tay.
- Mỗi lần cộng idempotent theo từng đơn để tín hiệu thanh toán trùng hay gửi lại không bao giờ cộng đôi.
- Đọc tỷ lệ từ cấu hình riêng từng merchant: không có mục cấu hình thì không tích; giá trị mặc định cài sẵn chỉ áp dụng khi mục đó tồn tại nhưng rỗng giá trị.
- Ghi mỗi lần cộng thành một mục sổ điểm và tăng số dư của khách trong một thao tác nguyên tử.
- Cho phép chỉ đọc để liệt kê và tra cứu các mục sổ điểm, giới hạn trong merchant của chính người dùng.
Non-Goals
- Đổi điểm, hạng thành viên và danh mục phần thưởng - 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 marketing khi tích điểm - thuộc Marketing.
- Cộng điểm cho đơn ẩn danh - chỉ khách đã định danh mới tích lũy (ràng buộc C-01).
3. Success Metrics
| Metric | Mụ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 có mục cấu hình và tỷ lệ dương) |
| Idempotency | Không cộng đôi - nhiều nhất một mục sổ điểm cho mỗi đơn |
| Độ chính xác | Số dư bằng tổng các mục tích điểm của khách |
| Độ trễ | Việc cộng xong trong luồng xác nhận thanh toán, không làm chậm hoàn tất đơn |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Customer | Tự động tích điểm và thấy số dư tăng |
| Owner | Đặt tỷ lệ và yên tâm mỗi đơn đã thanh toán đều tích đúng |
| Manager | Xem hoạt động điểm và số dư của thành viên |
Luồng cốt lõi: đơn đã thanh toán gắn với khách hàng → đọc tỷ lệ của merchant → tính điểm từ tổng đơn → ghi một mục sổ điểm và tăng số dư, một lần cho mỗi đơn.
5. User Stories
- Là customer, tôi muốn điểm tự động cộng vào số dư khi đơn được thanh toán, để được thưởng mà không phải làm gì.
- Là owner, tôi muốn tỷ lệ cấu hình riêng từng merchant, để kiểm soát cách chi tiêu quy đổi thành điểm.
- Là owner, tôi muốn tín hiệu thanh toán trùng không bao giờ cộng đôi, để sổ điểm luôn đáng tin.
- Là manager, tôi muốn liệt kê các mục sổ điểm của một khách, để xem số dư được tích lũy ra sao.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Cộng điểm khi đơ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 thanh toán - thanh toán đơn thông thường và thanh toán theo phiếu bàn | URD-PTS-001 |
| FR-2 | Idempotent theo từng đơn - dừng sớm nếu đơn đã được cộng điểm | URD-PTS-002 |
| FR-3 | Tỷ lệ đọc từ cấu hình riêng từng merchant: không có mục cấu hình thì không cộng; giá trị mặc định cài sẵn chỉ áp dụng khi mục đó tồn tại nhưng rỗng giá trị | URD-PTS-003 |
| FR-4 | Điểm = tổng đơn ÷ tỷ lệ, làm tròn xuống điểm nguyên; tỷ lệ không dương hoặc kết quả bằng không thì bỏ qua (ghi log, không cộng) | URD-PTS-001 |
| FR-5 | Trong một thao tác nguyên tử: ghi mục sổ điểm (mang theo điểm, tỷ lệ và đơn gốc) và tăng số dư; roll back cùng nhau khi lỗi | URD-PTS-001..002 |
| FR-6 | Liệt kê và tra cứu chỉ đọc các mục sổ điểm, giới hạn trong merchant của chính người dùng | URD-PTS-001 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong URD Loyalty; PRD này tham chiếu thay vì lặp lại.
7. Non-Functional Requirements
| Area | Yêu cầu |
|---|---|
| Data integrity | Mục sổ điểm và lần tăng số dư ghi cùng nhau, nguyên tử - không đổi số dư mà thiếu mục tương ứng |
| Idempotency | Nhiều nhất một mục cho mỗi đơn, đảm bảo bằng việc kiểm tra đơn đã được cộng điểm hay chưa |
| Tenancy & authz | Mọi thao tác giới hạn trong merchant của chính người dùng; phần liệt kê chỉ đọc cần quyền xem loyalty |
| Độ chính xác | Tính tiền / điểm dùng độ chính xác thập phân cố định; điểm làm tròn xuống đơn vị nguyên |
| Performance | Việc cộng chạy trong luồng xác nhận thanh toán, không làm chậm hoàn tất đơn |
| i18n | Nhãn / trạng thái hướng người dùng song ngữ (Tiếng Anh / Tiếng Việt) |
8. UX & Flows
Tích điểm không có UI riêng - nó chạy phía sau khi thanh toán hoàn tất. Số dư hiện trong hồ sơ khách hàng; các mục sổ điểm xem được qua phần liệt kê chỉ đọc.
9. Data & Domain
| Khái niệm | Vai trò |
|---|---|
| Mục sổ điểm | Bản ghi tích điểm chỉ thêm - điểm, tỷ lệ và đơn gốc, giới hạn trong merchant |
| Số dư điểm khách hàng | Số dư đang chạy, tăng nguyên tử cùng mỗi lần cộng |
| Tỷ lệ quy đổi riêng từng merchant | Tỷ lệ cấu hình cho merchant; dùng mặc định khi mục rỗng giá trị |
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ên và domain model của sale.
10. Dependencies & Assumptions
Phụ thuộc vào
- Định danh khách hàng (Khách hàng) - giữ số dư 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.
- Cấu hình riêng từng merchant - cung cấp tỷ lệ; bắt buộc (không có mục cấu hình → không tích).
Giả định
- Đơn gắn với một khách hàng đã định danh (đơn ẩn danh không tích, C-01).
- Merchant có một mục cấu hình (thiếu thì bỏ qua hoàn toàn việc tích); giá trị mặc định cài sẵn chỉ áp dụng khi mục đó rỗng giá trị.
- Tín hiệu 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ỏi | Giảm thiểu / trạng thái |
|---|---|
| Tín hiệu thanh toán trùng / gửi lại có thể cộng đôi | Idempotent theo từng đơn - kiểm tra đơn đã được cộng điểm hay chưa trước khi cộng (C-02) |
| Lần cộng và lần tăng số dư có thể lệch nhau khi lỗi một phần | Cả hai ghi nguyên tử; 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ác | Tỷ 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ích | Mở: định nghĩa đường thu hồi / đảo điểm đã tích |
12. Release Plan & Launch Criteria
| Aspect | Kế hoạch |
|---|---|
| Phase | P1 (nền tảng) - xem feature catalog của URD |
| Rollout | Tất cả merchant, không feature flag - mục cấu hình riêng từng merchant là opt-in trên thực tế (không có mục → không tích) |
| Migration | Không (sổ điểm mới; tỷ lệ lấy từ cấu hình) |
| Launch criteria | Đơn gắn khách đã thanh toán cộng điểm một lần; số dư khớp sổ điểm; tín hiệu trùng không cộng đôi; tỷ lệ đọc theo từng merchant |
| Monitoring | Lượng cộng điểm theo merchant, phát hiện cộng đôi (đơn có nhiều hơn một mục), 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 thanh toán đơn thông thường hay theo phiếu bàn.
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 đã có một mục cho đơn, lần cộng bị bỏ qua.
Tỷ lệ đến từ đâu? Từ cấu hình tỷ lệ quy đổi riêng từng merchant. Phải có mục cấu hình thì việc tích mới chạy; giá trị mặc định cài sẵn chỉ áp dụng khi mục đó tồn tại nhưng rỗng giá trị.
Điểm tính thế nào? Tổng đơn ÷ tỷ lệ, làm tròn xuống điểm nguyên. 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
- URD: Loyalty - Tích điểm
- PRD liên quan: Đổi điểm & Hạng (
RDM, kế hoạch) - xem URD-RDM - Module: Khách hàng thân thiết - URD
- Developer: @nx/sale customer-points