PRD: Chiến dịch SMS
| Module | Marketing (EXT-02) | PRD ID | PRD-CMP-001 |
| Status | Planned | Owner | Marketing squad |
| Date | 2026-03-13 | Version | v0.1 |
| Packages | mq-sms · @nx/identity · @nx/core | URD | CMP |
TL;DR
Cung cấp cho Marketing một kênh gửi SMS thực sự để tin nhắn tới được điện thoại khách hàng, không chỉ nằm trong queue. Một module
mq-smsđộc lập bọc lấy provider SMS của VNPAY, mộtApplicationSMSComponentnối nó vào identity, và consumer đầu tiên - OTP request và verification - chứng minh kênh hoạt động trọn vẹn. Đâ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. Context & Problem
Tính năng Chiến dịch & Tự động hóa của module Marketing cần một cách để thực sự gửi tin nhắn tới khách hàng. Theo Non-Goals của module, KICKO không tự xây hạ tầng gửi tin - mà tích hợp một provider bên ngoài. Hôm nay chưa có đường gửi SMS nào cả: không thành phần nào trong nền tảng có thể chuyển một tin nhắn văn bản tới nhà mạng, nên cả xác thực (OTP) lẫn bất kỳ chiến dịch tương lai nào đều không thể tới điện thoại khách hàng.
Increment này dựng phần nền cho việc gửi SMS - tích hợp provider bên ngoài, application component 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 (OTP). Bản thân việc gửi chiến dịch tới phân khúc sẽ được xếp lên trên sau này; xây kênh trước sẽ tháo nút cho cả auth lẫn marketing.
2. Goals & Non-Goals
Goals
- Dựng module third-party
mq-smsbọc lấy provider SMS của VNPAY (request helpers, request/response models, controller). - Thêm
ApplicationSMSComponentvào identity và tích hợp việc gửi SMS vào application. - Nạp cấu hình provider SMS (credentials, environment) qua configuration service, với seeding idempotent (upsert) và xử lý migration linh hoạt.
- Xây consumer SMS đầu tiên - OTP request và verification - với một SMS OTP sender và một log-only sender cho non-prod.
Non-Goals
- Bản thân việc gửi chiến dịch tới phân khúc (URD-CMP-001) - gửi một chiến dịch theo kế hoạch tới phân khúc khách hàng được 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).
- Xây 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 | Đường gửi SMS trả về xác nhận từ provider cho request hợp lệ; lỗi được hiển thị, không bị âm thầm bỏ qua |
| Khả năng giao OTP | OTP request → SMS được giao → verify thành công trọn vẹn |
| An toàn cấu hình | Cấu hình SMS 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 | Cùng kênh đó có thể được một campaign sender tương lai gọi 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 |
Core scenarios: cấu hình provider SMS VNPAY một lần → một luồng application (OTP request) yêu cầu kênh SMS gửi tin → mq-sms dựng một request VNPAY đã mã hóa 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ủa provider SMS được nạp từ configuration, để đổ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 không bị hỏng khi boot.
- Là Marketing owner, tôi muốn một kênh gửi SMS có thể tái sử dụng, để 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 hàng mà không phải làm thêm phần provider.
- Là developer, tôi muốn một log-only sender ở non-prod, để chạy thử luồng SMS mà không tốn tin nhắn thật.
6. Functional Requirements
| # | Requirement | URD ref |
|---|---|---|
| FR-1 | Cung cấp module third-party mq-sms mở ra một đường gửi SMS (controller + request/response models) | URD-CMP-001 |
| FR-2 | Tích hợp provider SMS của VNPAY qua request helpers và các constants/types của VNPAY | URD-CMP-001 |
| FR-3 | Mã hóa payload SMS trước khi gửi tới provider | URD-CMP-001 |
| FR-4 | Cung cấp ApplicationSMSComponent trong identity để application gọi gửi SMS | URD-CMP-001 |
| FR-5 | Nạp config provider SMS (credentials, environment) qua configuration service, seed bằng upsert (idempotent) | URD-CMP-001 |
| FR-6 | Dung thứ cấu hình SMS thiếu lúc startup/migration mà không làm hỏng boot | URD-CMP-001 |
| FR-7 | Cung cấp OTP request và verification trên kênh SMS, với một SMS OTP sender và một log-only sender cho non-prod | URD-CMP-001 |
| FR-8 | Tập trung cấu hình OTP vào configuration service; hash OTP secret qua Bun.password | 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 | Payload SMS được mã hóa trước khi tới provider; OTP secret được hash (Bun.password), không bao giờ lưu dạng rõ |
| Khả năng cấu hình | Credentials/environment của provider nằm trong configuration, không trong code; đổi được mà không redeploy |
| Khả năng phục hồi | Cấu hình SMS thiếu/không hợp lệ được dung thứ lúc startup; lỗi được hiển thị thay vì làm sập application |
| Idempotency | Seeding config dùng upsert - các lần startup/migration lặp lại hội tụ về một bản ghi |
| Khả năng quan sát | Có một log-only sender cho non-prod để các luồng kiểm thử được mà không gửi thật |
| i18n | Nội dung OTP hướng người dùng hỗ trợ song ngữ ({ en, vi }) |
8. UX & Flows
Trong increment này, kênh chưa có màn hình riêng hướng merchant; nó được các luồng application gọi (OTP hôm nay, gửi chiến dịch sau). Credentials của provider được quản lý qua configuration.
9. Data & Domain
| Entity | Vai trò |
|---|---|
| SMS request / response models | Hình dạng của một SMS gửi đi và phần xác nhận từ provider (mq-sms) |
TMQSMSClientConfig | Type cấu hình client provider (credentials, endpoint) |
| Config provider SMS | Cấu hình provider theo từng environment trong INTEGRATION config group, với trường environment |
| Config OTP | Cấu hình OTP tập trung trong configuration service |
| 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.
- Configuration service của
@nx/core- nạp config provider/OTP, seeding upsert, migration. @nx/identity- nơi đặtApplicationSMSComponentvà controller/service của OTP.
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). Bun.passwordcó sẵn để hash OTP.- 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 sau mq-sms; một provider thứ hai có thể gắn vào sau cùng component |
| Config SMS thiếu có thể làm hỏng boot | Startup/migration được làm dung thứ với config SMS vắng mặt |
| Provider gặp sự cố / lỗi giao tin | Lỗi được hiển thị tới phía gọi; non-prod dùng log-only sender |
| Chi phí gửi thật khi kiểm thử | Log-only sender cho các môi trường non-prod |
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 identity |
| Migration | Config provider SMS được seed vào INTEGRATION config group bằng upsert; thêm trường environment; dung thứ config thiếu |
| Launch criteria | OTP request → SMS được giao → verify được kiểm trọn vẹn; seeding config idempotent qua các lần khởi động lại; config thiếu không làm hỏng startup |
| 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 tới khách hàng 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) được 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 ở đây nếu đây là PRD Marketing? OTP hướng auth, nhưng nó là consumer đầu tiên và cốt lõi của đúng kênh SMS 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 module third-party mq-sms bọc lại. Provider nằm sau kênh để có thể thay hoặc mở rộng.
Credentials được quản lý thế nào? Qua configuration service (INTEGRATION group), với trường environment và seeding upsert idempotent - không cần redeploy để đổi.
Ở non-prod hoặc khi SMS chưa được cấu hình thì sao? Một log-only sender đứng thay cho việc gửi thật, và config SMS thiếu được dung thứ lúc startup nên boot không bị hỏng.
References
- URD: Marketing - Chiến dịch & Tự động hóa - requirements (vùng CMP)
- Module: Marketing - tổng quan + truy vết
- Developer: @nx/outreach - package phía thu thập