PRD: Yêu cầu kinh doanh
| Module | Khách hàng (CORE-09) | PRD ID | PRD-INQ-001 |
| Status | Shipped | Owner | Customer squad |
| Date | 2026-04-06 | Version | v1.0 |
| Packages | @nx/outreach · @nx/core | URD | INQ |
TL;DR
Cho phép một khách tiềm năng gửi yêu cầu kinh doanh từ trang marketing công khai - thông tin liên hệ, thông tin doanh nghiệp, và một lời nhắn - và cung cấp cho đội sales back-office một tín hiệu theo thời gian thực ngay khi một lead xuất hiện. Mỗi inquiry được theo dõi qua vòng đời rõ ràng NEW → assigned → replied → converted/lost, nên không lead nào đến mà không được nhìn thấy và mỗi lần theo dõi đều có audit trail.
1. Context & Problem
Trang marketing Overture công khai là nơi khách tiềm năng liên hệ, nhưng một lead chỉ có giá trị nếu đội sales nhìn thấy và xử lý nó. Nếu không có đường đi thu thập-và-thông-báo có cấu trúc, các inquiry hoặc nằm im trong hộp thư hoặc buộc đội phải poll một danh sách - lead trở nên cũ, quyền sở hữu không rõ ràng, và không có ghi nhận ai đã trả lời hay inquiry được giải quyết ra sao. Khi KICKO nhắm tới các doanh nghiệp HKD/SME qua đăng ký tự phục vụ, phễu lead đầu vào phải đáng tin cậy và có trách nhiệm rõ ràng.
Feature này thu thập inquiry như một record hạng nhất trong @nx/outreach, đẩy một tín hiệu WebSocket theo thời gian thực tới admin khi gửi, và theo dõi mỗi lead qua một vòng đời được kiểm soát để sales có thể assign, trả lời, và giải quyết nó.
2. Goals & Non-Goals
Goals
- Thu thập một inquiry từ trang công khai với thông tin liên hệ, thông tin doanh nghiệp, và một lời nhắn trong một lần gửi.
- Thông báo cho admin theo thời gian thực qua WebSocket ngay khi một inquiry mới được gửi - không cần polling.
- Theo dõi việc assign, trả lời, chuyển đổi, và lý do thất bại của mỗi inquiry qua một vòng đời (NEW → assigned → replied → converted/lost).
Non-Goals
- Engine chiến dịch Email / SMS (Dự kiến - xem URD §7).
- Phân khúc và nhắm mục tiêu khách hàng.
- Phân tích giá trị trọn đời của inquiry / lead.
3. Success Metrics
| Metric | Target / signal |
|---|---|
| Độ trễ thông báo | Inquiry mới hiện ra cho admin theo thời gian thực (đẩy WebSocket dưới một giây), không phải bằng polling |
| Độ đầy đủ khi thu thập | 100% lần gửi công khai được lưu với thông tin liên hệ + thông tin doanh nghiệp + lời nhắn |
| Trách nhiệm với lead | Mỗi inquiry hiển thị người được assign, tác giả/thời điểm trả lời, và một kết quả cuối |
| Thời gian phản hồi đầu tiên | Thời gian trung vị NEW → replied theo mỗi merchant có xu hướng giảm |
4. Personas & Use Cases
| Persona | Mục tiêu trong feature này |
|---|---|
| Site Visitor (Lead) | Gửi một inquiry từ trang công khai mà không cần tài khoản |
| Sales | Thấy lead mới ngay lập tức, nhận chúng, trả lời, và giải quyết là converted hoặc lost |
| Owner / Admin | Theo dõi lượng lead đầu vào và đảm bảo không inquiry nào bị bỏ sót |
Core scenarios: một visitor gửi một inquiry → nó được lưu là NEW và admin được thông báo theo thời gian thực → một sales rep assign nó cho chính mình → trả lời (ghi nhận tác giả + thời điểm) → đánh dấu converted hoặc lost kèm lý do.
5. User Stories
- Là một site visitor, tôi muốn gửi một inquiry với thông tin liên hệ và thông tin doanh nghiệp của mình kèm một lời nhắn, để doanh nghiệp có thể theo dõi với tôi.
- Là một sales rep, tôi muốn được thông báo theo thời gian thực khi một inquiry mới đến, để tôi có thể phản hồi nhanh mà không cần poll một danh sách.
- Là một sales rep, tôi muốn assign một inquiry cho chính mình, để quyền sở hữu rõ ràng.
- Là một sales rep, tôi muốn trả lời một inquiry và có lần trả lời cùng thời điểm của tôi được ghi nhận, để việc theo dõi có thể kiểm tra được.
- Là một sales rep, tôi muốn đánh dấu một inquiry là converted hoặc lost (kèm lý do), để kết quả của lead được ghi lại.
6. Functional Requirements
| # | Requirement | URD ref |
|---|---|---|
| FR-1 | Thu thập một inquiry từ endpoint gửi công khai với thông tin liên hệ, thông tin doanh nghiệp, và lời nhắn; inquiry mới bắt đầu ở status NEW | URD-INQ-001 |
| FR-2 | Khi gửi, phát ra một thông báo WebSocket theo thời gian thực tới admin mang theo id của inquiry, type, tên, email, tên doanh nghiệp, subject, và thời điểm tạo | URD-INQ-002 |
| FR-3 | Thông báo được publish lên topic INQUIRY_SUBMITTED, fan-out tới một room cấp-toàn-bộ và một room theo từng inquiryId để có thể nhắm tới một inquiry cụ thể | URD-INQ-002 |
| FR-4 | Theo dõi việc assign, trả lời (tác giả + thời điểm), chuyển đổi, và lý do thất bại của một inquiry | URD-INQ-003 |
| FR-5 | Đưa một inquiry qua vòng đời NEW → assigned → replied → converted/lost | URD-INQ-004 |
| FR-6 | Quản lý inquiry qua CRUD (find / find-by-id / count / create / update / delete), mỗi cái được gate bởi một resource InquiryPermissions.* | URD-INQ-003..004 |
Toàn bộ nội dung requirement và tiêu chí chấp nhận nằm trong Customer URD. PRD này tham chiếu tới chúng thay vì lặp lại.
7. Non-Functional Requirements
| Area | Requirement |
|---|---|
| Phân phối thời gian thực | WebSocket emitter được Redis hậu thuẫn và chạy ở chế độ single hoặc cluster từ env; thông báo fan-out qua các instance |
| Suy giảm nhẹ nhàng | Nếu socket service chưa sẵn sàng, lần gửi vẫn lưu inquiry và thông báo no-op kèm một cảnh báo - việc thu thập không bao giờ thất bại do đường đi thông báo |
| Tenancy & authz | Các endpoint quản lý inquiry được scope theo merchant (x-merchant-id) và gate bởi InquiryPermissions; lần gửi công khai không cần xác thực |
| Data integrity | Mọi record inquiry dùng soft-delete, giữ lại lịch sử lead |
| i18n | Nhãn/status hướng tới người dùng là song ngữ ({ en, vi }) |
8. UX & Flows
Các màn hình chính: form inquiry công khai nằm trên trang marketing Overture; danh sách inquiry back-office, chi tiết, và các điều khiển vòng đời (kèm badge/toast báo có lead mới theo thời gian thực) nằm trong apps/client.
9. Data & Domain
| Entity | Vai trò |
|---|---|
Inquiry | Record lead - thông tin liên hệ, thông tin doanh nghiệp, lời nhắn, type, status, người được assign, lần trả lời, và kết quả (lý do converted/lost) |
| WebSocket topic / room | Topic INQUIRY_SUBMITTED (observation/outreach/inquiry/submitted); một room collection cộng với một room theo từng inquiryId để phân phối có nhắm mục tiêu |
Chỉ ở mức khái niệm - schema đầy đủ và các bất biến nằm trong Outreach domain model.
10. Dependencies & Assumptions
Phụ thuộc vào
@nx/outreach- sở hữu record inquiry, vòng đời CRUD, và WebSocket component.@nx/core-schema.ts/model.tsinquiry dùng chung và các primitive base WebSocket emitter / socket-event.- Redis - hậu thuẫn WebSocket emitter cho việc fan-out xuyên instance.
Giả định
- Trang Overture công khai render form inquiry và post tới endpoint gửi.
- Một subscriber phía client (badge sidebar / toast thời gian thực) trong
apps/clienttiêu thụ thông báo. - Việc gửi email (SMTP) nằm ngoài phạm vi module này; việc theo dõi diễn ra qua vòng đời, không qua feature này.
11. Risks & Open Questions
| Risk / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Socket service ngừng → admin bỏ lỡ thông báo | Lần gửi vẫn lưu; thông báo no-op kèm cảnh báo, nên inquiry không bao giờ bị mất - admin vẫn thấy nó trong danh sách |
| Fan-out thông báo qua các instance | Emitter Redis-hậu-thuẫn ở chế độ cluster xử lý phân phối đa-instance |
| Spam / lạm dụng lead trên một endpoint công khai | Mở: cân nhắc rate-limiting / captcha trên lần gửi công khai |
| Không có kênh theo dõi email | Ngoài phạm vi; engine chiến dịch là Dự kiến trong URD |
12. Release Plan & Launch Criteria
| Aspect | Plan |
|---|---|
| Phase | P2 - xem URD feature catalog (INQ) |
| Rollout | Tất cả merchant; không feature flag |
| Migration | Không (các trường schema/model inquiry được thêm trong @nx/core) |
| Launch criteria | Lần gửi công khai lưu một inquiry NEW; admin nhận thông báo thời gian thực đầu-cuối; vòng đời assign → reply → converted/lost được kiểm chứng |
| Monitoring | Lượng inquiry theo merchant, tỷ lệ gửi thông báo thành công/thất bại, thời gian NEW → replied |
13. FAQ
Admin có phải refresh để thấy inquiry mới không? Không - một thông báo WebSocket được đẩy khi gửi, nên một lead mới hiện ra theo thời gian thực.
Điều gì xảy ra nếu WebSocket service ngừng khi một inquiry được gửi? Inquiry vẫn được lưu; thông báo bị bỏ qua kèm một cảnh báo. Admin vẫn thấy nó trong danh sách inquiry - việc thu thập không bao giờ phụ thuộc vào đường đi thông báo.
Một visitor có thể gửi inquiry mà không có tài khoản không? Có - endpoint gửi công khai không cần xác thực. Việc quản lý inquiry (find/assign/reply/resolve) cần xác thực và được gate bởi permission.
Gửi một inquiry có gửi email cho lead không? Không - không có kênh email/SMS trong module này. Việc theo dõi được ghi nhận qua vòng đời inquiry.
Các status của inquiry là gì? NEW → assigned → replied → converted/lost, kèm một lý do lost được ghi nhận khi áp dụng.
References
- URD: Customer - Sales Inquiries (vùng INQ)
- Module: Khách hàng - tổng quan + traceability
- Developer: @nx/outreach · Outreach domain model