PRD: Chiến dịch SMS
| Module | Marketing | PRD ID | PRD-CMP-001 |
| Trạng thái | Sẵn sàng dev | FEAT | CMP |
| Epic | — | Plane | BANA-1546 |
| Ngày | 2026-03-13 | Phiên bản | v0.1 |
| Gói | @nx/outreach | URD | CMP |
| Surface | Backend | ||
| Phụ trách | Phát Nguyễn | ||
TL;DR
Dựng cho Marketing một kênh gửi SMS thực sự - tích hợp provider VNPAY cùng khả năng gửi SMS trong luồng đăng nhập - được kiểm chứng qua consumer đầu tiên là OTP request/verify. Việc gửi OTP-qua-SMS thật hiện đang tạm tắt (non-prod dùng mã bypass) trong khi chờ provider sẵn sàng; đây là đường gửi cốt lõi mà việc gửi chiến dịch tới phân khúc theo kế hoạch (URD-CMP-001) sẽ tái sử dụng.
1. Bối cảnh & Vấn đề
Tính năng Chiến dịch & Tự động hóa của Marketing cần một cách để thực sự gửi tin tới khách hàng - mà hôm nay chưa có đường gửi SMS nào. Không thành phần nào trong nền tảng có thể chuyển một tin nhắn tới nhà mạng, nên cả xác thực (OTP) lẫn mọi chiến dịch tương lai đều không tới được điện thoại khách. Theo Non-Goals của module, BANA tích hợp một provider bên ngoài thay vì tự xây hạ tầng gửi tin.
Increment này đặt phần nền - tích hợp provider bên ngoài, khả năng sử dụng nó, và cấu hình provider/credential - rồi vận hành thử bằng consumer cụ thể đầu tiên là OTP. Việc gửi chiến dịch tới phân khúc xếp lên trên sau; xây kênh trước sẽ tháo nút cho cả auth lẫn marketing.
2. Goals & Non-Goals
Goals
- Dựng phần tích hợp provider SMS bọc lấy provider SMS của VNPAY (dựng request, hình dạng request/response, một đầu vào gửi).
- Thêm khả năng gửi SMS vào luồng đăng nhập và nối việc gửi SMS vào application.
- Nạp cấu hình provider SMS (credentials, environment) qua cấu hình tập trung, với seeding idempotent và migration linh hoạt.
- Xây consumer đầu tiên - OTP request và verification - với bộ gửi OTP qua SMS đã được nối. Một bộ gửi chỉ-ghi-log đã được hiện thực cho non-prod; OTP qua điện thoại hiện tạm tắt việc gửi SMS và chấp nhận một mã bypass để kiểm thử.
Non-Goals
- Bản thân việc gửi chiến dịch tới phân khúc (URD-CMP-001) - xếp lên trên kênh này, không thuộc increment này.
- Tự động hóa theo kích hoạt / drip (URD-CMP-002) và A/B testing & báo cáo (URD-CMP-003).
- Hạ tầng gửi tin vượt quá việc tích hợp provider VNPAY bên ngoài (theo Non-Goals của module).
- Gửi qua email / kênh khác.
3. Success Metrics
| Metric | Mục tiêu / tín hiệu |
|---|---|
| Sẵn sàng của kênh | Request hợp lệ trả về xác nhận từ provider; lỗi được hiển thị, không âm thầm bỏ qua |
| Khả năng giao OTP | OTP request → verify thành công trọn vẹn (việc gửi OTP-qua-SMS thật hiện tạm tắt; non-prod dùng mã bypass) |
| An toàn cấu hình | Cấu hình thiếu/không hợp lệ không làm sập startup; seeding idempotent qua các lần khởi động lại |
| Sẵn sàng tái sử dụng | Một campaign sender tương lai gọi được cùng kênh đó mà không phải làm lại phần provider |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Khách hàng (người nhận) | Nhận OTP (và sau này là tin chiến dịch) trên điện thoại |
| Người dùng đang xác thực | Yêu cầu và verify một OTP để hoàn tất đăng nhập |
| Owner / Manager (Marketing) | Sau này tái sử dụng kênh này để tiếp cận phân khúc qua chiến dịch |
| Người vận hành nền tảng | Cấu hình credentials/environment của VNPAY mà không phải redeploy code |
Kịch bản chính: cấu hình provider SMS VNPAY một lần → một luồng application (OTP request) yêu cầu kênh gửi tin → kênh dựng request (mặc định dạng rõ, hoặc đã mã hóa qua biến thể secure-send) và gửi đi → người nhận nhận được tin → OTP verify xác nhận mã.
5. User Stories
- Là người dùng đang xác thực, tôi muốn nhận OTP qua SMS và verify nó, để hoàn tất đăng nhập an toàn.
- Là người vận hành nền tảng, tôi muốn credentials và environment được nạp từ cấu hình, để đổi provider/environment mà không phải thay đổi code.
- Là người vận hành nền tảng, tôi muốn cấu hình SMS thiếu vẫn được dung thứ lúc startup, để các môi trường không có SMS vẫn boot.
- Là Marketing owner, tôi muốn một kênh SMS tái sử dụng được, để việc gửi chiến dịch tới phân khúc theo kế hoạch tiếp cận được khách mà không phải làm thêm phần provider.
- Là developer, tôi muốn một bộ gửi chỉ-ghi-log ở non-prod, để chạy thử luồng SMS mà không tốn tin thật.
6. Functional Requirements
| # | Requirement | URD ref |
|---|---|---|
| FR-1 | Cung cấp phần tích hợp provider SMS mở ra một đường gửi SMS (đầu vào gửi + hình dạng request/response) | URD-CMP-001 |
| FR-2 | Tích hợp provider SMS của VNPAY qua việc dựng request riêng cho provider | URD-CMP-001 |
| FR-3 | Cung cấp một biến thể secure-send có mã hóa (khóa chung suy ra từ ECDH + AES-256-CBC) cho payload SMS; đường gửi mặc định (OTP dùng) gửi dạng rõ | URD-CMP-001 |
| FR-4 | Cung cấp khả năng gửi SMS trong luồng đăng nhập để application gọi gửi SMS | URD-CMP-001 |
| FR-5 | Nạp config provider SMS (credentials, environment) qua cấu hình tập trung, seed idempotent | URD-CMP-001 |
| FR-6 | Dung thứ cấu hình SMS thiếu lúc migration (đăng ký một client rỗng thay vì lỗi); bản ghi config provider luôn được seed nên startup tìm thấy config | URD-CMP-001 |
| FR-7 | Cung cấp OTP request và verification trên kênh SMS, với bộ gửi OTP qua SMS đã được nối; một bộ gửi chỉ-ghi-log đã được hiện thực nhưng không phải cấu nối đang dùng - OTP qua điện thoại hiện tạm tắt việc gửi SMS và chấp nhận một mã bypass ở non-prod | URD-CMP-001 |
| FR-8 | Tập trung cấu hình OTP vào cấu hình tập trung; hash mã OTP bằng hàm băm một chiều | URD-CMP-001 |
Toàn văn requirement và acceptance criteria nằm trong URD Marketing. PRD này tham chiếu chúng thay vì lặp lại.
7. Non-Functional Requirements
| Lĩnh vực | Requirement |
|---|---|
| Bảo mật | Có sẵn một biến thể secure-send có mã hóa cho payload SMS (đường mặc định/OTP là dạng rõ); mã OTP được băm một chiều, không bao giờ lưu dạng rõ |
| Khả năng cấu hình | Credentials/environment của provider nằm trong cấu hình, không trong code; đổi được mà không redeploy |
| Khả năng phục hồi | Cấu hình SMS thiếu được dung thứ lúc migration (đăng ký một client rỗng); lỗi được hiển thị thay vì làm sập application |
| Idempotency | Seeding config hội tụ - các lần migration lặp lại lắng về một bản ghi |
| Khả năng quan sát | Một bộ gửi chỉ-ghi-log đã được hiện thực cho non-prod; trên thực tế OTP qua điện thoại tạm tắt việc gửi và một mã bypass giúp verify kiểm thử được mà không gửi thật |
| i18n | Nội dung OTP hướng người dùng là song ngữ (tiếng Anh + tiếng Việt) |
8. UX & Flows
Trong increment này kênh chưa có màn hình riêng hướng merchant; các luồng application gọi nó (OTP hôm nay, gửi chiến dịch sau). Credentials của provider được quản lý qua cấu hình.
9. Data & Domain
| Khái niệm | Vai trò |
|---|---|
| Hình dạng request / response SMS | Hình dạng của một SMS gửi đi và phần xác nhận từ provider |
| Cấu hình client provider | Thiết lập kết nối tới provider (credentials, endpoint) |
| Config provider SMS | Cấu hình provider theo từng environment trong khu vực cấu hình tích hợp, với một thiết lập environment |
| Config OTP | Cấu hình OTP tập trung trong cấu hình tập trung |
| OTP record | OTP đã phát hành/đã hash dùng cho request + verify |
Chỉ là khái niệm - schema đầy đủ và chi tiết provider nằm trong tài liệu outreach của lập trình viên.
10. Dependencies & Assumptions
Phụ thuộc vào
- Provider SMS của VNPAY - phần tích hợp nhà mạng bên ngoài mà kênh bọc lại.
- Cấu hình tập trung - nạp config provider/OTP, seeding idempotent, migration.
- Dịch vụ đăng nhập - nơi đặt khả năng gửi SMS và luồng OTP request/verify.
Giả định
- Credentials SMS VNPAY hợp lệ và một environment được cung cấp cho mỗi deployment (hoặc SMS được tắt có chủ đích).
- Hàm băm một chiều có sẵn để hash OTP secret.
- Một campaign sender tương lai sẽ tái sử dụng kênh này thay vì tích hợp provider riêng.
11. Risks & Open Questions
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Việc gửi chiến dịch tới phân khúc (URD-CMP-001) chưa được xây trên kênh này | Kênh + OTP ra trước; gửi chiến dịch là increment kế tiếp - PRD giữ trạng thái Planned cho tới lúc đó |
| Phụ thuộc một provider duy nhất (VNPAY) | Kênh trừu tượng hóa provider; một provider thứ hai có thể gắn vào sau cùng khả năng đó |
| Config SMS thiếu có thể làm hỏng boot | Migration dung thứ config vắng mặt (client rỗng); bản ghi config luôn được seed nên startup tìm thấy một config |
| Provider gặp sự cố / lỗi giao tin | Lỗi được hiển thị tới phía gọi; non-prod dựa vào một mã bypass với việc gửi tạm tắt |
| Chi phí gửi thật khi kiểm thử | OTP qua điện thoại tạm tắt việc gửi và dùng một mã bypass ở non-prod (bộ gửi chỉ-ghi-log cũng đã được hiện thực) |
12. Release Plan & Launch Criteria
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P2 - kênh gửi SMS cho Chiến dịch & Tự động hóa |
| Rollout | Kênh sẵn sàng ở nơi có config VNPAY; consumer OTP bật trong luồng đăng nhập |
| Migration | Config provider SMS được seed vào khu vực cấu hình tích hợp một cách idempotent; thêm thiết lập environment; dung thứ config thiếu |
| Launch criteria | OTP request → verify được kiểm trọn vẹn (việc gửi OTP-qua-SMS thật hiện tạm tắt; non-prod dùng mã bypass); seeding config idempotent qua các lần migration; bản ghi config provider được seed nên startup có một config |
| Monitoring | Tỷ lệ gửi SMS thành công/thất bại, tỷ lệ verify OTP thành công, các response lỗi từ provider |
13. FAQ
Cái này đã gửi chiến dịch marketing chưa? Chưa. Increment này cung cấp kênh SMS và consumer đầu tiên của nó (OTP). Việc gửi chiến dịch tới phân khúc (URD-CMP-001) xếp lên trên ở increment sau - vì vậy PRD này vẫn ở trạng thái Planned.
Vì sao OTP lại nằm trong PRD Marketing? OTP hướng auth, nhưng nó là consumer đầu tiên và cốt lõi của đúng kênh mà chiến dịch sẽ tái sử dụng. Chứng minh kênh qua OTP giúp giảm rủi ro cho việc gửi marketing.
Nó dùng provider nào? SMS VNPAY, được phần tích hợp provider SMS bọc lại để có thể thay hoặc mở rộng.
Credentials được quản lý thế nào? Qua cấu hình tập trung (khu vực tích hợp), với một thiết lập environment và seeding idempotent - không cần redeploy để đổi.
Ở non-prod hoặc khi SMS chưa được cấu hình thì sao? OTP qua điện thoại tạm tắt việc gửi thật và chấp nhận một mã bypass ở non-prod (một bộ gửi chỉ-ghi-log cũng đã được hiện thực). Config provider thiếu được dung thứ lúc migration, và bản ghi config luôn được seed nên startup tìm thấy một config.
References
- URD: Marketing - Chiến dịch & Tự động hóa - requirements (vùng CMP)
- Module: Marketing - URD
- Developer: @nx/outreach - package phía thu thập