PRD: Đăng ký, quản lý thiết bị & thiết bị ngoại vi
| Module | Thiết bị (CORE-04) | PRD ID | PRD-DEV-001 |
| Trạng thái | In-progress | Chủ sở hữu | Device squad |
| Ngày | 2026-05-19 | Phiên bản | v0.1 |
| Package | @nx/commerce · @nx/signal · apps/client · sale-renderer · sale-main | URD | DEV · MON · PRN · SCN · SBX · NFC |
TL;DR
Cho một tổ chức một nơi duy nhất để đăng ký, quản lý và giám sát phần cứng vận hành KICKO - máy POS, ứng dụng di động và web, cùng các thiết bị ngoại vi. Mỗi thiết bị có một định danh ổn định (header
x-device-info, tự đăng ký lúc đăng nhập lần đầu), một gán merchant tùy chọn, một vòng đời trạng thái có kiểm soát, và một màn hình quản lý đội thiết bị tìm kiếm được ở back-office; máy in, máy quét, SoundBox, SoftPOS và một heartbeat mỗi 5 phút đều gắn vào bản ghi đó. Kết quả: chủ sở hữu thấy và điều khiển được toàn bộ đội thiết bị, và runtime luôn biết một session thuộc về thiết bị nào.
1. Bối cảnh & Vấn đề
Merchant chạy KICKO trên hỗn hợp máy POS, ứng dụng di động và client web, mỗi cái kèm thiết bị ngoại vi (máy in, máy quét, SoundBox). Một entity Device và định danh D_YYYYMMDD_<snowflakeId> của nó đã tồn tại trong model commerce, nhưng chủ sở hữu không có màn hình ở back-office để quản lý đội thiết bị, và runtime không tạo hay tham chiếu một bản ghi thiết bị một cách nhất quán. Thiếu điều này, chủ sở hữu không thể liệt kê hay kiểm toán phần cứng, một session không thể gắn tin cậy vào một thiết bị vật lý, và không có vòng đời có kiểm soát giữa "đã đăng ký" và "đã ngừng dùng".
Increment này khép lại khoảng trống trên hai mặt: một trang quản lý thiết bị đầy đủ ở back-office để quản lý đội thiết bị, và định danh thiết bị lúc chạy (header x-device-info cùng tự động đăng ký lúc đăng nhập) để mọi session phân giải về một bản ghi thiết bị. Các mối quan tâm về thiết bị ngoại vi và tình trạng được xây trên bản ghi thiết bị này thay vì đứng riêng.
2. Mục tiêu & Không phải mục tiêu
Mục tiêu
- Một trang thiết bị ở back-office (danh sách, tạo, sửa) với form chia phần: thông tin chung, cấu hình phần cứng, cấu hình phần mềm, và cài đặt khác.
- Định danh thiết bị lúc chạy qua header
x-device-info; một bản ghi thiết bị được tự động đăng ký và kích hoạt lúc đăng nhập ứng dụng lần đầu, và được tái dùng cho thiết bị đã có. - Gán merchant tùy chọn trên thiết bị - một thiết bị gắn vào tổ chức với một gán tùy chọn tới một merchant.
- Khả năng tìm kiếm thiết bị qua stack tìm kiếm (Typesense device collection với tìm kiếm trường mô tả).
- Một vòng đời trạng thái có kiểm soát (
NEW → ACTIVATED → DEACTIVATED → SUSPENDED → ARCHIVED) với soft-delete và mã thiết bị duy nhất trong phạm vi tổ chức. - Stack thiết bị ngoại vi & tình trạng xây trên bản ghi thiết bị: máy in (ESC/POS), máy quét mã vạch, SoundBox, và một màn hình tình trạng dựa trên heartbeat kèm vô hiệu hóa từ xa.
Không phải mục tiêu
- Đấu nối backend API VNPAY Terminal (bảng đã có; backend chưa kết nối - phát hiện QE).
- Tích hợp máy in nhãn và hỗ trợ máy POS Windows.
- Chấp nhận thanh toán không tiếp xúc SoftPOS / NFC - Dự kiến (P3).
- Điều khiển ngăn kéo đựng tiền và UI quản lý driver thiết bị ngoại vi nâng cao.
- Ứng dụng màn hình bếp, phục vụ và giao hàng.
3. Success Metrics
| Metric | Mục tiêu / tín hiệu |
|---|---|
| Phủ định danh | 100% session ứng dụng phân giải về một bản ghi thiết bị qua x-device-info (không session mồ côi) |
| Tự đăng ký | Đăng nhập lần đầu trên thiết bị mới tạo đúng một bản ghi thiết bị; đăng nhập sau tái dùng nó |
| Khả kiến đội thiết bị | Chủ sở hữu liệt kê, tìm kiếm và sửa được mọi thiết bị đã đăng ký từ back-office |
| Độ chính xác tình trạng | Trạng thái online/offline khớp ngưỡng heartbeat 5 phút / offline 15 phút |
| Độ tin cậy ngoại vi | Lỗi in/quét/SoundBox hiển thị rõ ràng; thanh toán không bao giờ bị chặn bởi SoundBox mất kết nối |
4. Personas & Use Cases
| Persona | Mục tiêu |
|---|---|
| Chủ sở hữu | Đăng ký, quản lý và giám sát đội thiết bị; gán thiết bị cho merchant; vô hiệu hóa từ xa thiết bị bị xâm phạm |
| Quản lý | Xem thiết bị và tình trạng, cấu hình thiết bị ngoại vi trong phạm vi |
| Thu ngân | Vận hành POS trên thiết bị đã kích hoạt; ghép nối và dùng máy in / máy quét / SoundBox |
Kịch bản chính: chủ sở hữu đăng ký một thiết bị (hoặc nó tự đăng ký lúc đăng nhập lần đầu) → gán cho merchant và kích hoạt → runtime mang định danh thiết bị trong x-device-info → thiết bị ngoại vi ghép nối vào thiết bị → chủ sở hữu giám sát tình trạng qua heartbeat và có thể vô hiệu hóa từ xa.
5. User Stories
- Là chủ sở hữu, tôi muốn một trang back-office để liệt kê, tạo và sửa thiết bị, để quản lý toàn bộ đội thiết bị ở một nơi.
- Là chủ sở hữu, tôi muốn một thiết bị tự đăng ký và kích hoạt lúc đăng nhập ứng dụng lần đầu, để nhân viên không phải đăng ký phần cứng thủ công.
- Là chủ sở hữu, tôi muốn gán một thiết bị cho merchant (tùy chọn), để giới hạn một thiết bị theo đơn vị kinh doanh.
- Là chủ sở hữu, tôi muốn tìm thiết bị theo tên, định danh, mã, trạng thái và loại, để nhanh chóng tìm một thiết bị cụ thể.
- Là chủ sở hữu, tôi muốn mỗi thiết bị mang một định danh ổn định trong header
x-device-info, để mọi session gắn vào một thiết bị đã biết. - Là thu ngân, tôi muốn máy in, máy quét và SoundBox ghép nối vào thiết bị của mình, để in hóa đơn, quét sản phẩm và nghe xác nhận thanh toán.
- Là quản trị viên, tôi muốn thấy tình trạng thiết bị và vô hiệu hóa từ xa thiết bị bị xâm phạm, để bảo vệ đội thiết bị.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Đăng ký thiết bị với tên i18n, loại, và tổ chức; tự sinh định danh D_YYYYMMDD_<snowflakeId> | URD-DEV-001..003 |
| FR-2 | Vòng đời trạng thái NEW → ACTIVATED → DEACTIVATED → SUSPENDED → ARCHIVED; chỉ chuyển hợp lệ; soft-delete | URD-DEV-004..009 |
| FR-3 | Mã thiết bị, khi được cung cấp, duy nhất trong phạm vi tổ chức | URD-DEV-011 |
| FR-4 | Một thiết bị tự đăng ký và kích hoạt lúc đăng nhập ứng dụng lần đầu; thiết bị đã có được tái dùng | URD-DEV-013 |
| FR-5 | Tìm thiết bị theo tên, định danh, mã, trạng thái và loại (Typesense collection) | URD-DEV-014 |
| FR-6 | Gán / bỏ gán một thiết bị cho merchant; việc gán là tùy chọn | URD-DEV-016 |
| FR-7 | Ghi thông tin phần cứng và phần mềm cho mỗi thiết bị | URD-DEV-017..018 |
| FR-8 | Định danh thiết bị mang trong header x-device-info trên các lời gọi API | URD-MON-001 |
| FR-9 | Heartbeat mỗi 5 phút; offline sau 15 phút; màn hình tình trạng (online/offline, lần thấy cuối, phiên bản app); vô hiệu hóa từ xa | URD-MON-001..005 |
| FR-10 | Máy in (ESC/POS), máy quét mã vạch và SoundBox ghép nối vào một thiết bị và hiển thị lỗi rõ ràng khi thất bại | URD-PRN · URD-SCN · URD-SBX |
| FR-11 | Chấp nhận không tiếp xúc SoftPOS / NFC trên Android qua VNPAY KYC (Dự kiến) | URD-NFC-001..004 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong URD Thiết bị. PRD này tham chiếu chúng thay vì lặp lại.
7. Non-Functional Requirements
| Lĩnh vực | Yêu cầu |
|---|---|
| Toàn vẹn dữ liệu | Một thiết bị gắn vào tổ chức với một gán merchant tùy chọn; định danh bất biến; bản ghi dùng soft-delete |
| Định danh | Mọi lời gọi API mang định danh thiết bị trong x-device-info; một session đang hoạt động mỗi thiết bị |
| Phân tách & phân quyền | Thao tác giới hạn theo tổ chức (và merchant nơi được gán); truy cập API yêu cầu xác thực (JWT hoặc Basic Auth) |
| Hiệu năng / quy mô | Tìm kiếm thiết bị dựa trên index (Typesense); nhịp heartbeat (5 phút) giới hạn tải ghi |
| Khả năng phục hồi | SoundBox mất kết nối không bao giờ chặn thanh toán; lỗi in/quét hiển thị rõ, không âm thầm bỏ qua |
| i18n | Tên thiết bị và nhãn hướng người dùng là song ngữ ({ en, vi }); ESC/POS in tiếng Việt qua code page 28 |
8. UX & Flows
Màn hình chính: trang thiết bị ở back-office trong apps/client - danh sách/bảng, tạo, sửa, và một form chia phần (chung, cấu hình phần cứng, cấu hình phần mềm, cài đặt khác), nằm dưới navigation gốc đã xác thực. Các luồng thiết bị ngoại vi POS (quét, in, SoundBox, SoftPOS) nằm trong sale-renderer với lớp native Tauri trong sale-main.
9. Data & Domain
| Entity | Vai trò |
|---|---|
Device | Bản ghi thiết bị - tên i18n, loại, trạng thái, định danh, tổ chức, relation merchant tùy chọn, thông tin phần cứng/phần mềm |
| Thông tin phần cứng | Nhà sản xuất, model, serial, IMEI, MAC, processor, RAM, lưu trữ, màn hình, pin |
| Thông tin phần mềm | OS, phiên bản OS, phiên bản app, firmware, cập nhật cuối, driver thiết bị ngoại vi |
| Device session | Một session đang hoạt động gắn vào một thiết bị, mở lúc đăng nhập |
| Device search collection | Typesense collection lập chỉ mục thiết bị (gồm cả trường mô tả) |
Chỉ mang tính khái niệm - schema và bất biến đầy đủ trong commerce domain model.
10. Dependencies & Assumptions
Phụ thuộc vào
- Commerce (
@nx/commerce) - sở hữu entityDevice, quyền sở hữu của tổ chức, gán merchant tùy chọn, thông tin phần cứng/phần mềm, và vòng đời trạng thái. - Signal (
@nx/signal) - edge thời gian thực cho sự kiện thiết bị/thanh toán và device search collection. - Client apps -
apps/client(quản lý back-office),sale-renderer(UI POS),sale-main(lớp native Tauri với plugin USB/NFC/máy in/máy quét).
Giả định
- Tổ chức đã tồn tại; một merchant tồn tại khi dùng việc gán.
- Ứng dụng gửi một machine UID ổn định trong header
x-device-info. - Phần cứng được chứng nhận (VNPAY V-POS, Sunmi T2) sẵn có cho kịch bản máy POS.
11. Risks & Open Questions
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
Trùng bản ghi thiết bị nếu x-device-info không ổn định qua các lần đăng nhập | Tự đăng ký tái dùng bản ghi đã có theo machine UID; định danh bất biến |
| Backend VNPAY Terminal chưa đấu nối (bảng đã có) | Ngoài phạm vi - phát hiện QE đã đánh dấu; theo dõi cho increment sau |
| SoftPOS / NFC phụ thuộc VNPAY KYC và phần cứng Android | Dự kiến (P3); ẩn tùy chọn trên iOS, chặn khi NFC không khả dụng |
| Tải ghi heartbeat ở quy mô đội thiết bị | Giới hạn bởi nhịp 5 phút; xem lại nhịp nếu tải tăng |
| Xóa dữ liệu từ xa khi thiết bị offline | Đưa vào queue và áp dụng lúc kết nối lại |
12. Release Plan & Launch Criteria
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | DEV / POS / PRN / SCN / MON = P2 (In-progress); MOB / WEB / SBX = P1 (Built); NFC = P3 (Planned) - xem catalog tính năng URD |
| Triển khai | Tất cả tổ chức; không feature flag |
| Di trú | Dọn model - gỡ organizerId, thêm relation merchant, sửa unique index; không cần backfill dữ liệu |
| Tiêu chí ra mắt | Đã kiểm chứng list/create/edit ở back-office; đã kiểm chứng tự đăng ký lúc đăng nhập lần đầu; định danh x-device-info phân giải trên mọi session; tìm kiếm thiết bị trả về kết quả mong đợi |
| Giám sát | Tỷ lệ tự đăng ký, số session mồ côi, độ chính xác online/offline của heartbeat, tỷ lệ lỗi thiết bị ngoại vi |
13. FAQ
Tôi có phải đăng ký thủ công mọi thiết bị không? Không - một thiết bị tự đăng ký và kích hoạt lúc đăng nhập ứng dụng lần đầu, và thiết bị đã có được tái dùng. Trang back-office dùng để quản lý và sửa đội thiết bị.
Một thiết bị thuộc về merchant hay tổ chức? Nó thuộc về tổ chức, với một gán tùy chọn tới một merchant. Không có cột organizerId trên model.
Cái gì định danh một thiết bị lúc chạy? Header x-device-info (một machine UID), thay thế trường deviceId cũ.
SoundBox mất kết nối có chặn một thanh toán không? Không - nếu SoundBox mất kết nối, thanh toán vẫn thành công; thông báo được âm thầm bỏ qua.
SoftPOS có sẵn chưa? Chưa - SoftPOS / NFC là Dự kiến (P3), chỉ Android, và yêu cầu VNPAY KYC.
References
- URD: Thiết bị - DEV · MON · PRN · SCN · SBX · NFC · MOB · WEB · POS
- Module: Thiết bị - tổng quan + truy vết
- Developer: @nx/commerce · @nx/signal · domain model
- Apps: sale-renderer · sale-main · client