PRD: Thiết lập & vòng đời khuyến mãi
| Module | Campaign | PRD ID | PRD-PRM-001 |
| Trạng thái | Sẵn sàng dev | FEAT | PRM |
| Epic | — | Plane | BANA-1492 |
| Ngày | 2026-03-23 | Phiên bản | v1.0 |
| Gói | @nx/pricing | URD | PRM |
| Surface | Client · Chủ/QL | ||
| Phụ trách | Phát Nguyễn | ||
TL;DR
Merchant tạo một khuyến mãi trong một thao tác - phương thức giảm giá (phần trăm hoặc cố định), điều kiện áp dụng/nguồn/mục tiêu, khung thời gian hiệu lực, giới hạn sử dụng - rồi cho nó chạy qua vòng đời rõ ràng
DRAFT → ACTIVATED → DEACTIVATED/EXPIRED/ARCHIVED. Mỗi khuyến mãi nằm gọn trong merchant của chính nó, nên mỗi gian hàng tự sở hữu ưu đãi của mình từ đầu đến cuối.
1. Bối cảnh & Vấn đề
Merchant muốn dùng giảm giá có mục tiêu để thúc đẩy doanh số, nhưng pricing mới chỉ biết fare và điều kiện của fare - chưa có khái niệm khuyến mãi, chưa có phương thức giảm giá, chưa có vòng đời. Merchant không có cách nào tạo một giảm giá có cấu trúc, nói rõ nó áp cho ai và cái gì, giới hạn số lần dùng, hay lên lịch khi nào nó chạy.
Increment này biến khuyến mãi thành một khái niệm pricing hạng nhất. Điều kiện được tổng quát hóa để fare và khuyến mãi dùng chung một model điều kiện áp dụng/nguồn/mục tiêu; ghép một khuyến mãi với phương thức giảm giá cho merchant đầy đủ quyền tạo/sửa/xóa, một khung thời gian hiệu lực, một giới hạn sử dụng, và một vòng đời theo trạng thái. Mỗi khuyến mãi nằm gọn trong phạm vi của chính merchant sở hữu nó, nên mỗi gian hàng sở hữu danh mục ưu đãi của riêng mình.
2. Mục tiêu & Ngoài phạm vi
Mục tiêu
- Một khuyến mãi đi cùng phương thức giảm giá là khái niệm pricing hạng nhất, được tạo cùng phương thức và điều kiện trong một thao tác nguyên tử duy nhất.
- Một phương thức giảm giá trên khuyến mãi:
FIXED/PERCENTAGE, với một loại mục tiêu và một chiến lược phân bổ. - Một điều kiện tái sử dụng cho quy tắc áp dụng, nguồn và mục tiêu - chia sẻ với fare.
- Một vòng đời theo trạng thái mặc định
DRAFT, bao gồmDRAFT → ACTIVATED → DEACTIVATED / EXPIRED / ARCHIVED. - Một khung thời gian hiệu lực và một trường giới hạn sử dụng cho mỗi khuyến mãi (giới hạn được kiểm tra/tăng đếm ở thời điểm áp, sẽ đi cùng
APP). - Loại khuyến mãi
STANDARDvàBUY_GET. - Phạm vi theo từng merchant - mỗi khuyến mãi thuộc về đúng một merchant.
Ngoài phạm vi
- Tự áp / coupon thủ công khi thanh toán - thuộc Áp giảm giá (
APP, P2, URD-APP-001…003). - Tích/đổi điểm thân thiết - thuộc Khách hàng thân thiết.
- Gửi tin nhắn khuyến mãi - thuộc Marketing.
- Tính thuế - thuộc engine thuế của pricing.
3. Success Metrics
| Chỉ số | Mục tiêu / tín hiệu |
|---|---|
| Tính nguyên tử | 100% lần tạo khuyến mãi lưu khuyến mãi + phương thức + điều kiện cùng nhau, hoặc không lưu gì khi lỗi |
| Toàn vẹn vòng đời | Mỗi khuyến mãi nằm ở đúng một trạng thái trong tập vòng đời chuẩn, mặc định DRAFT (chưa thực thi kiểm tra thứ tự chuyển trạng thái - trạng thái đổi qua thao tác update chung) |
| Cô lập tenancy | Một merchant chỉ thấy và thay đổi khuyến mãi thuộc phạm vi của chính mình |
| Độ phủ thiết lập | Merchant có thể cấu hình ưu đãi phần trăm và cố định cùng điều kiện áp dụng/mục tiêu mà không cần kỹ sư hỗ trợ |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Owner | Tạo, kích hoạt và lưu trữ bất kỳ khuyến mãi nào của merchant |
| Manager | Soạn và quản lý khuyến mãi - phương thức, điều kiện, hiệu lực, giới hạn sử dụng |
Kịch bản cốt lõi: tạo một khuyến mãi cùng phương thức và điều kiện trong một bước → đặt khung thời gian hiệu lực và giới hạn sử dụng → kích hoạt → sau đó hủy kích hoạt, để hết hạn, hoặc lưu trữ.
5. User Stories
- Là một manager, tôi muốn tạo một khuyến mãi cùng phương thức giảm giá và điều kiện trong một bước, để ưu đãi được định nghĩa đầy đủ trong một thao tác duy nhất.
- Là một manager, tôi muốn chọn phương thức
FIXEDhoặcPERCENTAGEvới một loại mục tiêu và phân bổ, để giảm giá hoạt động đúng như chiến dịch cần. - Là một manager, tôi muốn định nghĩa điều kiện áp dụng, nguồn và mục tiêu, để khuyến mãi chỉ áp cho đúng khách hàng và sản phẩm.
- Là một manager, tôi muốn đặt một khung thời gian hiệu lực và một giới hạn sử dụng, để ưu đãi chạy trong một khoảng cố định và không bị dùng quá mức.
- Là một owner, tôi muốn đưa một khuyến mãi qua vòng đời của nó (kích hoạt, hủy kích hoạt, hết hạn, lưu trữ), để tôi kiểm soát khi nào một ưu đãi đang chạy.
- Là một owner, tôi muốn khuyến mãi chỉ gói gọn trong merchant của mình, để ưu đãi của tôi không bao giờ rò rỉ qua các gian hàng khác.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Tạo một khuyến mãi cùng phương thức và điều kiện trong một thao tác nguyên tử (tất cả hoặc không gì khi lỗi) | URD-PRM-001 |
| FR-2 | Trạng thái vòng đời DRAFT → ACTIVATED / DEACTIVATED / EXPIRED / ARCHIVED, mặc định DRAFT (trường trạng thái đã có; chưa có guard kiểm tra thứ tự chuyển trạng thái cho khuyến mãi) | URD-PRM-002 |
| FR-3 | Phương thức giảm giá FIXED / PERCENTAGE, với loại mục tiêu và chiến lược phân bổ | URD-PRM-001 |
| FR-4 | Định nghĩa điều kiện áp dụng, nguồn và mục tiêu qua điều kiện dùng chung | URD-PRM-003 |
| FR-5 | Loại khuyến mãi STANDARD và BUY_GET | URD-PRM-001 |
| FR-6 | Các trường khung thời gian hiệu lực trên khuyến mãi | URD-PRM-002 |
| FR-7 | Trường giới hạn sử dụng cho mỗi khuyến mãi, kèm helper kiểm tra giới hạn và tăng đếm nguyên tử; thực thi ở runtime chạy tại thời điểm áp và chưa hoạt động | URD-PRM-004 |
| FR-8 | Phạm vi theo từng merchant - mỗi khuyến mãi thuộc về một merchant, với tra cứu theo merchant và trạng thái | URD-PRM-001 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong Campaign URD. PRD này tham chiếu chúng thay vì lặp lại.
7. Non-Functional Requirements
| Khía cạnh | Yêu cầu |
|---|---|
| Toàn vẹn dữ liệu | Khuyến mãi, phương thức và điều kiện được tạo cùng nhau theo cách nguyên tử - lỗi một phần không để lại khuyến mãi ghi dở |
| Tính hợp lệ vòng đời | Trạng thái mặc định DRAFT và dùng các trạng thái vòng đời chuẩn (không trạng thái tự chế); chưa có state machine kiểm tra thứ tự chuyển trạng thái (khác với fare set vốn đã guard chuyển trạng thái) |
| Tenancy & authz | Mọi thao tác gói gọn trong merchant của chính người dùng; được kiểm soát bởi permission khuyến mãi |
| Tái sử dụng | Điều kiện được chia sẻ giữa fare và khuyến mãi - một model điều kiện, hai bên dùng |
| Cascade | Xóa một khuyến mãi sẽ cascade tới phương thức và điều kiện của nó |
| i18n | Nhãn/trạng thái hiển thị cho người dùng là song ngữ (tiếng Anh + tiếng Việt) |
8. UX & Flows
Màn hình chính (trong app quản trị của merchant): màn hình danh sách khuyến mãi, cùng tạo/sửa khuyến mãi cho phương thức, điều kiện, khung thời gian hiệu lực và giới hạn sử dụng.
9. Data & Domain
| Khái niệm | Vai trò |
|---|---|
| Khuyến mãi | Tài liệu khuyến mãi - loại, trạng thái, khung thời gian hiệu lực, giới hạn sử dụng, merchant sở hữu |
| Phương thức giảm giá | Phương thức giảm giá - FIXED/PERCENTAGE, loại mục tiêu, chiến lược phân bổ |
| Điều kiện | Điều kiện áp dụng/nguồn/mục tiêu dùng chung (tái sử dụng bởi fare và khuyến mãi) |
Chỉ ở mức khái niệm - schema và bất biến đầy đủ nằm trong pricing domain model và tài liệu promotion.
10. Dependencies & Assumptions
Phụ thuộc vào
- Điều kiện dùng chung - tổng quát hóa từ điều kiện fare để khuyến mãi và fare dùng chung một model điều kiện.
- Sản phẩm (Sản phẩm) - điều kiện mục tiêu tham chiếu sản phẩm và danh mục.
- Khách hàng (Khách hàng) - điều kiện áp dụng tham chiếu phân khúc khách hàng.
Giả định
- Kỳ vọng một khuyến mãi có phương thức hợp lệ trước khi kích hoạt (ràng buộc C-01); điều này chưa được thực thi trong code - kích hoạt là một thao tác đổi trạng thái thông thường, không có guard phương thức.
- Mỗi merchant sở hữu khuyến mãi của riêng mình; mọi khuyến mãi đều gắn với một merchant.
11. Risks & Open Questions
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Ghi khuyến mãi/phương thức/điều kiện có thể lệch khi lỗi một phần | Được tạo nguyên tử như một đơn vị - tất cả hoặc không gì |
| Tổng quát hóa điều kiện fare thành điều kiện dùng chung có thể phá vỡ các bên dùng fare | Điều kiện dùng chung đã được kiểm chứng trên cả fare và khuyến mãi |
| Khuyến mãi được cấu hình nhưng chưa áp khi thanh toán | Chấp nhận - áp giảm giá là tính năng APP riêng (P2); tính toán giảm giá ngoài phạm vi ở đây |
| Kích hoạt một khuyến mãi mà không có phương thức | Ràng buộc C-01 (cần phương thức trước khi kích hoạt) đã được nêu nhưng chưa thực thi - hiện chưa có guard kích hoạt; sẽ bổ sung cùng đường áp giảm giá |
12. Release Plan & Launch Criteria
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P1 (nền tảng) - xem URD feature catalog |
| Rollout | Tất cả merchant; không feature flag |
| Migration | Bản ghi khuyến mãi và phương thức giảm giá mới; điều kiện fare được tổng quát hóa thành điều kiện dùng chung; thêm quyền sở hữu theo merchant cho khuyến mãi |
| Tiêu chí ra mắt | Tạo nguyên tử lưu khuyến mãi + phương thức + điều kiện; trạng thái mặc định DRAFT và cập nhật trạng thái hoạt động được; cô lập theo từng merchant được kiểm chứng; danh sách phía client render được |
| Giám sát | Số khuyến mãi mỗi merchant, tỷ lệ lỗi tạo, lỗi chuyển trạng thái vòng đời |
13. FAQ
Phương thức và điều kiện của một khuyến mãi có được tạo riêng không? Không - khuyến mãi, phương thức và điều kiện được tạo cùng nhau trong một thao tác nguyên tử; khi lỗi không lưu gì.
Những phương thức giảm giá nào được hỗ trợ? FIXED và PERCENTAGE, mỗi loại có một loại mục tiêu và một chiến lược phân bổ.
Vòng đời là gì? Một khuyến mãi bắt đầu ở DRAFT và đi qua ACTIVATED → DEACTIVATED / EXPIRED / ARCHIVED.
Kích hoạt một khuyến mãi có áp giảm giá khi thanh toán không? Chưa - thiết lập và trường trạng thái vòng đời đã hoạt động, nhưng tự áp/coupon khi thanh toán là tính năng Áp giảm giá riêng (APP, P2). Tính toán giảm giá có trong codebase nhưng chưa được bật, nên việc tính giảm giá, thực thi giới hạn sử dụng và guard phương thức khi kích hoạt đều ngoài phạm vi ở đây.
Một khuyến mãi có thể chia sẻ qua nhiều merchant không? Không - mỗi khuyến mãi chỉ gói gọn trong phạm vi của đúng một merchant; một merchant chỉ thấy và thay đổi khuyến mãi của mình.
References
- URD: Chiến dịch - Thiết lập & Vòng đời khuyến mãi
- PRD liên quan: Áp giảm giá (
APP, kế hoạch) - Module: Chiến dịch - URD
- Developer: @nx/pricing · Promotions · domain model