Appearance
Đặc tả giao diện (UI Spec) — Hồ sơ bệnh án v2.3.0
Tham chiếu: PRD v2.0.0 | Ngày: 30/04/2026
Mục đích: mô tả màn hình, thay đổi, trạng thái, tương tác, copy hiển thị, tooltip và trường hợp cá biệt để FE/UI/QA triển khai thống nhất, đủ căn cứ triển khai và kiểm thử cột/trạng thái/validation.
Đọc trước:
decision-brief.md→B-PRE) Kiểm tra trước khi viết→B0) Hiện trạng UI→B1) Bản đồ màn hình→ cácSCRáp dụng →B-POST) Verification→B-QUALITY) Rà soát rủi ro thiếu sót.Văn phong: theo
templates/_LANGUAGE_RULES.md+templates/_STYLE_GUIDE.md. Heading + nhãn Mermaid/wireframe Việt-first. CTA:Lưu/Hủy/Áp dụng/Xác nhận. Mọi copy là tiếng Việt tự nhiên ngữ cảnh thẩm mỹ viện.Phụ lục mở rộng đã load: EXT-3 (Lifecycle UI mở rộng), EXT-4 (Field visibility tầng 3), EXT-5 (Config addendum), EXT-6 (Luồng coverage matrix), EXT-7 (Mobile interaction).
Lịch sử thay đổi
| Phiên bản | Ngày | Tác giả | Thay đổi |
|---|---|---|---|
| 2.3.0 | 30/04/2026 | PO/BA | Đồng bộ với permission-spec.md v1.0.0: thêm SCR-18 Compliance Audit Viewer (route /s/compliance/clinical-audit) cho phép Compliance officer + Admin/Ops + Medical Lead xem medical_record_access_log + emergency override sessions + anomaly + export audit Excel. SCR-18 có B2.1-B2.9 đầy đủ; B0.1 + B0.5 + B1.1 cập nhật; ngầm hiểu Day-1 hoặc Phase 2 tuỳ PD-PERM-004. |
| 2.2.0 | 30/04/2026 | PO/BA | Đóng các lỗ hổng nhất quán với PRD/SoT/dev-spec: (1) chuẩn hoá trợ lý cấu hình thành 6 bước (5 bước cấu hình + Kiểm tra sẵn sàng) ở B-PRE.2/B0.1/B0.5/B1.1/B1.2/B2.2/B2.7 SCR-04 + redo wireframe stepper. (2) Loại bỏ nhánh customer_id=NULL ở SCR-03/SCR-05 do dev-spec yêu cầu clinical_*.customer_id NOT NULL; walk-in chưa có hồ sơ phải tạo khách inline trước khi lưu lượt khám. (3) Thêm CTA "Tạo đơn từ lượt khám" trong danh sách lịch hẹn SCR-03. (4) Bổ sung luồng "Khách từ chối thủ thuật" (DEC-024) ở SCR-08/SCR-10 + B-edge case Nhóm 4. (5) Chuẩn hoá rule validation câu xác nhận tự gõ ở SCR-08 (≥20 ký tự, chứa "đồng ý"/"thực hiện", FE chặn dán). (6) Sửa lỗi search-replace live → đang hoạt động còn sót: B2.11 SCR-04 LIFECYCLE-001, B8.1 sự kiện. (7) Sửa "POS portal" → "Cổng tablet quầy theo token" cho SCR-15 + B-Mobile. (8) Việt hoá nhất quán: "stepper/empty state/job chạy lâu/step kế/Click → trợ lý/trạng thái rỗng/tác vụ chạy lâu/bước tiếp theo/Bấm". (9) Đổi "P0" thành "BA ưu tiên cao" trong copy hiển thị; vẫn giữ P0 trong code/log nội bộ. (10) Bổ sung trạng thái sử dụng kỹ thuật ở SCR-04c rõ hơn (cột tách bạch). (11) Đánh dấu lại "Sự kiện phân tích" ở B-PRE.2 thành ⚠ chưa xác nhận. |
| 2.1.0 | 30/04/2026 | PO/BA | Refactor một vòng ngôn ngữ: bỏ cụm dịch máy móc, chuẩn hóa copy người dùng nhìn thấy, giữ nguyên code literal. Bổ sung chi tiết UI cho SCR-01/02/03/04a/04b/04c/04e/04f/05/08/11/12. |
| 2.0.0 | 30/04/2026 | PO/BA | Refactor full theo glossary canonical 34 thuật ngữ + G3.7 cổng kiểm tra độ đầy đủ UI (B-PRE / B0.4 Field × nơi hiển thị / B0.5 Trạng thái×Màn hình / B-POST 12-checkpoint / B-QUALITY 15 rủi ro thiếu sót). Giữ 100% nội dung wireframe + luồng + copy. |
| 1.5.10 | 29/04/2026 | PO/BA | Bản cũ — bị thay thế |
Tài liệu đầu vào chuẩn
| File | Vai trò | Nếu xung đột |
|---|---|---|
SOURCE_OF_TRUTH.md | Nguồn sự thật chuẩn + Phương án đã chốt | Ưu tiên cao nhất |
EVIDENCE_PACK.md | Layout UI hiện tại, kiểm kê hiện trạng, ứng viên reuse | Ưu tiên bằng chứng code/màn hình |
prd.md | FR, vòng đời, rào phạm vi, công thức | Theo truth đã khóa |
Quy tắc: UI Spec là tài liệu dẫn xuất, không tự phát minh rule. Không suy diễn xóa: thành phần hiện hữu vắng mặt trong target → ghi nhận khoảng trống UI Spec hoặc lệch phạm vi, không phải kỳ vọng xóa. Mọi
REMOVE/HIDEphải có DEC/FR/PO approval.
B-PRE) Kiểm tra trước khi viết (BẮT BUỘC trước khi viết UI Spec)
B-PRE.1) Tìm component/page hiện có liên quan
bash
# Customer Detail tabs (CRM portal)
find diva-admin/src/modules/crm/pages/CustomerDetail.tsx
# Branch Detail tabs
find diva-admin/src/modules/user/pages/BranchDetail.tsx
# Order/Appointment forms
find diva-admin/src/modules/ecommerce/components/order/OrderForm/
find diva-admin/src/modules/ecommerce/components/appointment/AppointmentForm.tsx
# Permission v2 infra
grep -r "useGlobalStore.hasPermission" diva-admin/src/
# Existing notification + export patterns
grep -r "Export" diva-admin/src/modules/timekeeping/components/B-PRE.2) Bảng inventory đã check
| Hạng mục | Đã check | File / màn hiện có | Ghi chú |
|---|---|---|---|
| Page / đường dẫn hiện có | ✅ | crm/pages/CustomerDetail.tsx (16 tabs), user/pages/BranchDetail.tsx (3 tabs), ecommerce/pages/Appointments.tsx, ecommerce/pages/OrderCreate.tsx | Tái sử dụng 4 shell |
| Component có thể tái sử dụng | ✅ | XDetailLayout, XTable, XFileUpload, QStepper | Tái sử dụng 100% |
| Form/dialog liên quan | ✅ | AppointmentForm.tsx, OrderForm/index.tsx (4 step QStepper) | Mở rộng |
| Field/cột hiện có trên màn target | ✅ | Xem Evidence Pack mục 3 (As-Is UI Inventory) | Có baseline đầy đủ |
| CTA hiện có | ✅ | Lưu, Hủy, Tạo mới, Xóa (đã chuẩn VI) | Reuse |
| Bộ lọc / search hiện có | ✅ | Branch bộ lọc, Date range, Trạng thái bộ lọc ở Appointments | Mở rộng với badge BA trong bộ lọc |
| Trạng thái hiện có | ✅ | Khung tải dữ liệu, Trạng thái rỗng, Thông báo nhanh lỗi (Quasar) | Reuse |
| Điều kiện hiển thị theo quyền/role | ✅ | globalStore.hasPermission(moduleId, actionId) + branchModeFromRole() | Reuse infra; thêm 22 action mới |
| Trigger thông báo hiện có | ✅ | 130+ trigger codes (noti_appointment_*, noti_order_*) | Thêm 7 trigger clinical |
| Cột xuất dữ liệu hiện có | ✅ | ExportWorkingTimeSheet.tsx pattern (convertObjectsToRows) | Reuse pattern |
| Tooltip/hint | ✅ | q-tooltip Quasar component | Reuse |
| Mobile/responsive | ✅ | Quasar $q.screen.lt.md breakpoints | Reuse |
| Sự kiện phân tích | ⚠ | Chưa có inventory analytic chuẩn — cần xác nhận trước phát hành | Thêm event clinical (xem B8.1) |
B-PRE.3) Phân loại tái sử dụng (ref SOURCE_OF_TRUTH.md mục 4 Solution Lock)
| Phần tính năng | Phân loại | Bằng chứng | Phần cần bổ sung |
|---|---|---|---|
| Tab thứ 17 "Hồ sơ bệnh án" trong CustomerDetail | 🔧 Mở rộng | crm/pages/CustomerDetail.tsx | Thêm 1 tab + đường dẫn + component |
| Tab thứ 4 "Phòng khám" trong BranchDetail | 🔧 Mở rộng | user/pages/BranchDetail.tsx | Thêm 1 tab + trợ lý cấu hình 6 bước (5 bước cấu hình + Kiểm tra sẵn sàng) |
| Cảnh báo "cần BA" ở OrderForm bước 1 | 🔧 Mở rộng | ecommerce/components/order/OrderForm/OrderFormService.tsx | Thêm 1 banner + 1 cờ trường |
| Công tắc walk-in ở AppointmentForm | 🔧 Mở rộng | ecommerce/components/appointment/AppointmentForm.tsx | customer_id đã optional; thêm gợi ý UI |
| Form BA DL + TM | 🆕 Xây mới | Không có form BA | Renderer theo JSON Schema + các phần mở rộng được |
| Form 5 biểu mẫu dùng chung | 🆕 Xây mới | Không có | Render từ form_template |
| In + tải bản scan đã ký | 🆕 Xây mới | Có pattern print_invoice + reference_file | Component phòng khám riêng |
| Sổ khám bệnh + Sổ thủ thuật | 🆕 Xây mới | Không có sổ | Bảng danh sách dẫn xuất từ clinical_record |
| Trang xem an toàn (Sale) | 🆕 Xây mới | Không có | Trang riêng + bản xem an toàn |
| Bàn việc bác sĩ | 🆕 Xây mới | Không có | Trang riêng + truy vấn 6 nhóm việc |
| Phiếu khách tự khai | 🆕 Xây mới | Không có | Trang cổng KH chạy trên tablet quầy, mở bằng token một lần |
| Trang điều phối phòng khám | 🆕 Xây mới | Không có | Trang điều phối |
| Chốt ngày phòng khám | 🆕 Xây mới | Không có | Hộp thoại trong trang điều phối |
B0) Hiện trạng UI và quy ước thay đổi (As-Is + Quy ước thay đổi)
B0.1) Bảng kiểm kê đầy đủ
| UI ID | Màn / đường dẫn | Section | Block / field / action | Thứ tự hiện tại | Hành vi hiện tại | Permission/condition | Mobile? | Trạng thái thay đổi | Hành vi đích | Evidence |
|---|---|---|---|---|---|---|---|---|---|---|
| SCR-01-BLK-01 | /crm/customer/:id | Left panel | CustomerEWalletInformation | 1 | Wallet, sidebar info | All | Có (responsive) | KEEP | Không đổi | crm/pages/CustomerDetail.tsx |
| SCR-01-BLK-02 | /crm/customer/:id | Header | StatisticCumulativeCards | 2 | Stats KH | All | Có | KEEP | Không đổi | ↑ |
| SCR-01-BLK-03 | /crm/customer/:id | Tabs | 16 tabs hiện có | 3 | Navigate | Theo permission từng tab | Có | KEEP | Không đổi | ↑ |
| SCR-01-BLK-04 | /crm/customer/:id/clinical-record | Tabs | Tab thứ 17 "Hồ sơ bệnh án" | 17 | (chưa có) | clinical_record.access | Có | NEW | Tab mới + đường dẫn + component | DEC-029 |
| SCR-02-BLK-01 | /e/service-order/orders/create step 1 Service | OrderFormService | service, qty, price, doctor, note | (giữ nguyên) | Pick service | order.create | Có | KEEP | Không đổi | ecommerce/components/order/OrderForm/OrderFormService.tsx |
| SCR-02-BLK-02 | /e/service-order/orders/create step 1 | OrderFormService | (chưa có cảnh báo) | — | — | — | Có | NEW | Banner cảnh báo "Cần BA" + field flag needs_clinical_record | DEC-006 |
| SCR-03-BLK-01 | /e/service-order/appointment | AppointmentForm | customer_id (optional) | 8 | Optional ở GraphQL | All | Có | KEEP | Không đổi (đã optional walk-in OK) | AppointmentForm.tsx:58 |
| SCR-03-BLK-02 | /e/service-order/appointment | AppointmentForm | (chưa có walk-in toggle UI) | — | — | — | Có | NEW | Toggle "Khách walk-in" + hint | DEC-003 |
| SCR-03-BLK-03 | /e/service-order/appointment (list) | Bảng | (chưa có badge BA) | — | — | — | Có | NEW | Badge "Đã có BA" + bộ lọc trạng thái | DEC-002 |
| SCR-04-BLK-01 | /s/internal-settings/branch/:id | Tabs | 3 tabs (department, warehouse, service) | 1-3 | Navigate | branch.update | Có | KEEP | Không đổi | user/pages/BranchDetail.tsx |
| SCR-04-BLK-02 | /s/internal-settings/branch/:id/clinic-config | Tabs | Tab thứ 4 "Phòng khám" | 4 | (chưa có) | clinic_module.access | Có | NEW | Tab + trợ lý 6 bước (5 cấu hình + 1 kiểm tra sẵn sàng) | DEC-001, DEC-029, DEC-031 |
B0.2) Từ điển Trạng thái thay đổi
| Trạng thái | Ý nghĩa | Evidence bắt buộc |
|---|---|---|
KEEP | Giữ nguyên | Ghi rõ vẫn hiển thị ở target wireframe |
UPDATE | Đổi copy/layout/data | PRD FR/AC + ref file:line |
MOVE | Đổi vị trí, giữ behavior | UX luồng + ghi rõ trước/sau khu vực nào |
NEW | Thêm mới | PRD FR/AC ref |
REMOVE | Bỏ | DEC + FR/AC + PO approval (BẮT BUỘC ≥2 evidence) |
HIDE | Ẩn theo điều kiện | Permission/condition rõ |
B0.3) Tiêu chí hoàn thành B0
- [x] 100% UI hiện tại của 4 màn (CustomerDetail / BranchDetail / Appointments / OrderCreate) đã inventory
- [x] Không có block/field/action thiếu Trạng thái thay đổi
- [x] Mọi dòng có cột Evidence
- [x] Không có
REMOVE/HIDE(Day-1 chỉ KEEP/NEW/UPDATE) → không cần ≥2 evidence - [x] Target wireframe ở B2 hiển thị vùng
KEEPxung quanh update
B0.4) Ma trận Field × nơi hiển thị (12 cột) — BẮT BUỘC cho field mới/sửa
Mọi field mới/sửa đều có 1 dòng với 12 cột. Cell trống → không đạt G3.7.
| Field | Bảng danh sách | Chi tiết/Form | Hộp thoại | Xuất Excel | Tìm kiếm | Bộ lọc | Điều kiện theo quyền | Mobile | Thông báo | Trạng thái mặc định | Validation | Tooltip |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
branch.features.clinic_enabled | N/A | Có (toggle BranchDetail) | N/A | N/A | N/A | Có (bộ lọc CN có/không PK) | clinic_module.configure | Có | Có (noti_clinic_module_published) | false | BOOL | "Bật module Phòng khám cho chi nhánh này. Trạng thái mặc định tắt với chi nhánh spa thuần" |
clinic_module_publication.status | Có (cột "Trạng thái phát hành") | Có (BranchDetail tab Phòng khám) | N/A | Có (export trạng thái CN) | Có | Có (bộ lọc trạng thái live/paused/scheduled/...) | clinic_module.access | Có | Có | off | ENUM | "Trạng thái phát hành module: Tắt / Đang cấu hình / Đã sẵn sàng / Đã lập lịch / Đang hoạt động / Đã tạm dừng" |
service_clinical_classification.classification_status | Có (cột "Phân loại") | Có (form classification) | Có (popup mass classification — Phase 2) | Có | Có | Có (3 trạng thái) | clinic_module.configure | Có | N/A | unclassified | ENUM (mapped_requires_ba/explicitly_no_ba/unclassified) | "Phân loại dịch vụ — kỹ thuật: Cần bệnh án / Không cần bệnh án (đã xác nhận) / Chưa phân loại" |
clinical_record.profile_code | Có (cột "Mã BA") | Có | Có | Có | Có | N/A | clinical_record.view_summary | Có | Có | (auto FORMULA-001) | Pattern DVA-[TM|DL]-[CN]-[YYYY]-[NNNNN] | "Mã hồ sơ bệnh án chính: định danh duy nhất theo khách hàng, chi nhánh và loại phòng khám. Không reset theo năm" |
clinical_record.visit_log_number | Có (cột "STT sổ khám") | Có | N/A | Có | Có | N/A | clinical_record.view_summary | Có | N/A | (auto FORMULA-002) | Pattern DVA-[CN]-[NNNNN]/[YYYY] | "Số thứ tự sổ khám bệnh, reset theo năm. Mỗi lượt khám = 1 STT" |
clinical_record.procedure_log_number | Có (cột "STT sổ thủ thuật") | Có | N/A | Có | Có | N/A | clinical_record.view_summary | Có | N/A | (auto FORMULA-003) | Pattern DVA-[CN]-TT-[NNNNN]/[YYYY] | "Số thứ tự sổ thủ thuật, reset theo năm. Chỉ ca có kỹ thuật thủ thuật" |
clinical_record.status | Có (badge) | Có | N/A | Có | Có | Có | clinical_record.view_summary | Có | Có | draft | ENUM (draft/completed/printed/signed/superseded/archived) | "Trạng thái bệnh án lượt khám: Bản nháp / Đã hoàn thành / Đã in / Đã ký + scan đủ / Bản thay thế / Đã lưu trữ" |
clinical_form_instance.form_data | N/A | Có (form section expandable) | N/A | N/A (không export raw) | N/A | N/A | clinical_record.edit_medical_form (write) / view_medical_detail (read tầng 3) | Có | N/A | {} | JSON Schema từ form_template | "Nội dung phiếu biểu mẫu (JSONB). Backend validate theo JSON Schema trước khi lưu" |
clinical_record.diagnosis_codes (ICD-10 primary + secondary) | N/A | Có (dropdown searchable) | N/A | Có (cột chẩn đoán) | Có | Có (bộ lọc ICD chapter) | clinical_record.view_medical_detail (xem) / edit_medical_form (sửa) | Có | N/A | [] | ≥1 primary; ≤5 secondary | "Mã chẩn đoán theo ICD-10 (TT46/2018). 1 mã chính bắt buộc + tối đa 5 mã phụ" |
prescription.items | N/A | Có (table thuốc trong popup) | Có | Có (đơn thuốc) | N/A | N/A | clinical_record.edit_medical_form | Có | N/A | [] | ≥1 item nếu kê | "Danh mục thuốc trong đơn theo TT52/2017" |
customer_clinical_intake.token | N/A | N/A (token-based access) | N/A | N/A | N/A | N/A | customer_clinical_intake.open_session | Có (tablet) | N/A | (auto sinh) | UUID + expires_at = NOW + 15 phút | "Token một lần cho phiên khách tự khai. Hết hạn sau 15 phút" |
clinic_daily_close.closed_at | Có (lịch sử chốt ngày) | Có | Có (hộp thoại chốt) | Có | Có | Có (bộ lọc ngày chốt) | clinic_daily_close.close_branch_day | Có | Có (noti_medical_record_end_of_day) | NULL | TIMESTAMPTZ | "Thời điểm QL CN bấm 'Chốt ngày'. Cron tự ghi nhận trạng thái tại cutoff" |
medical_record_access_log.action | Có (audit trail) | Có | N/A | Có (audit export — chỉ Admin/Compliance) | Có | Có (bộ lọc action) | clinical_record.view_medical_detail (Admin audit) | N/A | Có (noti_medical_record_emergency_override) | (auto từ event) | ENUM (view_summary/view_medical_detail/print/upload_scan/export/emergency_override) | "Loại thao tác mở dữ liệu nhạy cảm tầng 3. Mọi emergency_override phải có lý do" |
B0.5) Ma trận Trạng thái × màn hình (6 trạng thái) — BẮT BUỘC cho mọi màn có data
| Màn / khối | Trạng thái mặc định | Đang tải | Trống | Lỗi + thử lại | Không có quyền | Thành công một phần |
|---|---|---|---|---|---|---|
| SCR-01 (CustomerDetail tab Hồ sơ bệnh án) | Danh sách BA của KH (50 dòng/trang) | Khung tải 5 dòng | "Khách chưa có hồ sơ bệnh án nào" + CTA "Tạo lượt khám mới" | "Không thể tải dữ liệu. Vui lòng thử lại." + nút Thử lại | Ẩn cả tab (guard đường dẫn) | N/A |
| SCR-04 (BranchDetail tab Phòng khám) | Hiện trợ lý cấu hình 6 bước | Lớp chờ xử lý trên bước hiện tại | "Chưa cấu hình" + CTA "Bắt đầu cấu hình" | Lỗi tại field + banner tổng | Ẩn cả tab | N/A (đi tuần tự từng bước, không cho lưu một phần) |
| SCR-04d (Phân loại dịch vụ — kỹ thuật) | Bảng 50 dịch vụ đang bán | Khung tải | "Chưa có dịch vụ đang bán tại CN này" | Thông báo nhanh "Không tải được — Thử lại" | Ẩn nút Lưu | Thông báo nhanh "Đã lưu X/Y dịch vụ. {Z} lỗi" |
| SCR-05 (Tạo lượt khám popup) | Form rỗng | Nút Lưu hiển thị đang xử lý | N/A | Lỗi tại field + banner | Khóa nút "Lưu" + tooltip | N/A |
| SCR-06 / SCR-07 (Form BA DL/TM) | Form rỗng + section mở rộng theo dịch vụ | Khung tải 3 phần | N/A | Lỗi tại field | Ẩn CTA "Hoàn thành" | "Đã lưu nháp lúc HH:mm" thông báo nhanh (autosave) |
| SCR-08 (5 biểu mẫu shared) | Thanh tab biểu mẫu + form theo khuôn | Khung tải | N/A | Lỗi tại field + banner | Ẩn CTA | N/A |
| SCR-09 (Xem trước PDF) | iframe PDF | "Đang tạo PDF..." spinner | N/A | "Không tạo được PDF. Thử lại" + nút Thử lại | Ẩn nút In | N/A |
| SCR-10 (Tải bản scan đã ký) | Drop zone + checklist scan | "Đang tải lên {N}/{M}..." progress | "Chưa có file scan" | "Tải lỗi {filename}. Thử lại" | Ẩn drop zone | "Đã tải {X}/{Y} file. {Z} lỗi" thông báo nhanh |
| SCR-11 / SCR-12 (Sổ khám / Sổ thủ thuật) | Bảng 50 dòng/trang | Khung tải | "Chưa có lượt khám trong khoảng {từ}-{đến}" | "Không tải được. Thử lại" | Ẩn đường dẫn | "Đã xuất {X}/{Y} dòng. {Z} dòng bị ẩn theo phân quyền" thông báo nhanh |
| SCR-13 (Trang xem an toàn — Sale) | Thẻ tóm tắt tầng 1+2 + từ điển cảnh báo | Khung tải | "Khách chưa có cảnh báo an toàn" | Thông báo nhanh | Ẩn đường dẫn | N/A |
| SCR-14 (Bàn việc bác sĩ) | 6 nhóm việc + số lượng + danh sách việc | Khung tải 6 thẻ | "Hôm nay không có việc nào tại CN này" | Thông báo nhanh + nút Thử lại | Ẩn đường dẫn | "Đã hoàn thành {X}/{Y} việc" badge |
| SCR-15 (Phiếu khách tự khai) | Form phiếu tự khai | Đang tải | N/A | Lỗi tại field + banner "Phiên đã hết hạn" nếu token expired | "Phiên đã hết hạn. Vui lòng nhờ lễ tân mở lại." | "Đã lưu {X}/{Y} câu trả lời" |
| SCR-16 (Trang điều phối) | Thẻ CN + cảnh báo lệch cấu hình | Khung tải 12 thẻ | "Chưa có CN nào đang hoạt động" | Thông báo nhanh + Thử lại | Ẩn đường dẫn | N/A |
| SCR-17 (Hộp thoại chốt ngày) | Hộp thoại xác nhận với count | Nút Chốt hiển thị đang xử lý | N/A | Lỗi tại field | Ẩn nút Chốt | "Đã chốt ngày. Còn {X} BA chưa scan đã gửi cảnh báo" thông báo nhanh |
| SCR-18 (Compliance Audit Viewer) | Bảng 50 events đầu trong 7 ngày + filter + anomaly count | Khung tải bảng + filter | "Không có event audit trong khoảng này." | "Không tải được audit. Thử lại." + Thử lại | Đường dẫn 401 (chỉ Compliance + Admin/Ops + Medical Lead) | "Đã xuất {X} dòng. Bấm tải về." thông báo nhanh |
B0.6) Quy ước ngôn ngữ giao diện sau refactor
Dùng bảng này khi viết label, thông báo nhanh, trạng thái rỗng, tooltip và wireframe. Code field/action/route vẫn giữ nguyên trong backtick; chỉ đổi câu chữ người dùng nhìn thấy.
| Cụm dễ máy móc | Cách viết trong UI | Dùng ở đâu |
|---|---|---|
| "Submit", "Confirm", "Save draft" | "Lưu", "Xác nhận", "Lưu nháp" | Nút thao tác |
| "Loading", "No data", "Error" | "Đang tải dữ liệu...", "Chưa có dữ liệu", "Không thể tải dữ liệu. Vui lòng thử lại." | Trạng thái màn hình |
| "Upload scan" | "Tải bản scan đã ký" | SCR-10, Bàn việc bác sĩ |
| "Preview impact" | "Xem trước tác động khi áp dụng" | Hộp thoại phát hành module |
| "Sales-safe view" | "Trang xem an toàn (Sale)" | CRM/Sale |
| "Doctor workbench" | "Bàn việc bác sĩ" | POS/Clinical |
| "Customer intake" | "Phiếu khách tự khai" | Tablet quầy |
| "Review intake" | "Rà soát phiếu tự khai" hoặc CTA "Nhận vào hồ sơ" | Bác sĩ/y tá |
| "Publication status" | "Trạng thái phát hành" | Branch Detail, Trang điều phối |
| "Runtime live gate" | "Điều kiện mở vận hành" | Mô tả kỹ thuật trong tooltip/copy nội bộ |
| "Field hidden by permission" | "Bị ẩn theo phân quyền" | Badge/placeholder dữ liệu tầng 3 |
| "Safe alert" | "Nhãn cảnh báo an toàn" | Sale, Customer Detail |
| "P0 record / P0 case" | "Bệnh án ưu tiên cao" | Copy hiển thị; mã P0 chỉ dùng trong code/log |
| "Stepper / 5-step stepper" | "Trợ lý cấu hình (6 bước)" | Mô tả wizard SCR-04 |
| "Click" (verb) | "Bấm" | Câu chỉ dẫn người dùng |
| "Empty state" | "Trạng thái rỗng" | Tài liệu nội bộ |
| "Job chạy lâu" / "long job" | "Tác vụ chạy lâu" | Mô tả hành vi |
Nguyên tắc copy: mỗi thông báo lỗi phải nói rõ người dùng cần làm gì tiếp theo. Ví dụ: không viết "Không hợp lệ"; viết "Vui lòng chọn ít nhất 1 mã ICD-10 chính".
B1) Bản đồ màn hình và hành trình
B1.1) Danh sách màn
| SCR | Tên | Đường dẫn | Loại | Mô tả |
|---|---|---|---|---|
| SCR-01 | Hồ sơ bệnh án (tab thứ 17 CustomerDetail) | /crm/customer/:id/clinical-record (CRM) hoặc /u/customer/:id/clinical-record (User) | 🔧 Mở rộng | Tab mới hiển thị Hồ sơ bệnh án chính + danh sách Bệnh án lượt khám |
| SCR-02 | Cảnh báo "cần BA" ở OrderForm bước Dịch vụ | /e/service-order/orders/create step 1 | 🔧 Mở rộng | Banner + cờ trường khi dịch vụ mapped_requires_ba |
| SCR-03 | AppointmentForm walk-in toggle | /e/service-order/appointment/create | 🔧 Mở rộng | Toggle "Khách walk-in" + badge BA trên danh sách |
| SCR-04 | BranchDetail tab Phòng khám | /s/internal-settings/branch/:id/clinic-config | 🔧 Mở rộng | Tab thứ 4 + trợ lý cấu hình 6 bước (5 bước cấu hình + Kiểm tra sẵn sàng) |
| SCR-04a..f | Sáu bước cấu hình phòng khám | (con của SCR-04) | 🆕 Xây mới | Bước 1 Loại PK / Bước 2 Giấy phép / Bước 3 Danh mục KT / Bước 4 Phân loại dịch vụ — kỹ thuật / Bước 5 Phân quyền / Bước 6 Kiểm tra sẵn sàng |
| SCR-05 | Tạo lượt khám (popup) | (popup) | 🆕 Xây mới | Form tạo appointment với walk-in toggle |
| SCR-06 | Form BA Da liễu | /e/service-order/clinical-records/:id/ba-dl | 🆕 Xây mới | Form 6 phần mở rộng được + danh sách ICD-10 |
| SCR-07 | Form BA Thẩm mỹ (4 phân hệ) | /e/service-order/clinical-records/:id/ba-tm | 🆕 Xây mới | Form tự hiện phần tương ứng theo dịch vụ POS |
| SCR-08 | Form 5 biểu mẫu dùng chung | (popup từ SCR-06/07) | 🆕 Xây mới | Cam đoan / cam kết / đơn thuốc / phiếu dị ứng / phiếu theo dõi điều trị |
| SCR-09 | Xem trước PDF + In bộ hồ sơ | (popup) | 🆕 Xây mới | iframe xem trước PDF + nút In |
| SCR-10 | Tải bản scan đã ký | (popup từ SCR-01) | 🆕 Xây mới | Vùng thả file + mapping file ↔ biểu mẫu + checklist scan |
| SCR-11 | Sổ khám bệnh | /e/service-order/clinical-visit-log | 🆕 Xây mới | Bảng lượt khám + bộ lọc + xuất dữ liệu |
| SCR-12 | Sổ thủ thuật | /e/service-order/clinical-procedure-log | 🆕 Xây mới | Tương tự SCR-11, chỉ ca thủ thuật |
| SCR-13 | Trang xem an toàn (Sale) | /crm/customer/:id/sales-safe-clinical | 🆕 Xây mới | Tab dành cho Sale, chỉ tầng 1+2 + từ điển cảnh báo |
| SCR-14 | Bàn việc bác sĩ | /e/service-order/doctor-workbench | 🆕 Xây mới | 6 nhóm việc trong ngày |
| SCR-15 | Phiếu khách tự khai | /p/customer-clinical-intake/:token | 🆕 Xây mới | Cổng KH (tablet quầy), mở bằng token 15 phút, KH tự điền |
| SCR-16 | Trang điều phối phòng khám | /e/service-order/clinic-ops-dashboard | 🆕 Xây mới | Trang điều phối rollout toàn chuỗi |
| SCR-17 | Chốt ngày phòng khám (hộp thoại) | (hộp thoại trong SCR-16) | 🆕 Xây mới | Hộp thoại xác nhận + log clinic_daily_close |
| SCR-18 | Trang Compliance Audit Viewer | /s/compliance/clinical-audit | 🆕 Xây mới | Compliance officer xem medical_record_access_log + emergency override + anomaly + export audit; Day-1 hoặc Phase 2 tuỳ PD-PERM-004 |
B1.2) Hành trình end-to-end
Hành trình theo vai trò:
| Vai trò | Entry point | Đường màn | Kết quả đầu ra |
|---|---|---|---|
| Admin/Ops | Settings → Branch Detail | SCR-04 → SCR-04a..f → kiểm tra sẵn sàng → phát hành | Module ở live, UI clinical xuất hiện cho team CN |
| Bác sĩ | Bàn việc bác sĩ | SCR-14 → SCR-05 → SCR-06/07 → SCR-08 → SCR-09 | Bệnh án signed |
| Y tá | Bàn việc bác sĩ (nhóm need_scan) | SCR-14 → SCR-10 | Scan checklist đủ |
| Lễ tân | POS Order hoặc Appointment | SCR-02 → SCR-05 (popup) | Lượt khám tạo |
| Tư vấn viên (Sale) | Customer Detail (CRM) | SCR-13 → form chuyển BS | Phiếu chuyển bác sĩ tư vấn |
| QL CN | Trang điều phối phòng khám | SCR-16 → SCR-17 | Đã chốt ngày |
| Khách hàng | Tablet quầy (token) | SCR-15 | Phiếu khách tự khai gửi |
| Ops | Trang điều phối phòng khám | SCR-16 (toàn chuỗi) | Lệch cấu hình + gửi cảnh báo |
B2) Chi tiết SCR (theo thứ tự phụ thuộc)
Mỗi SCR phải có đủ: ngữ cảnh, bố cục, field/cột chính, tương tác, phân quyền, trạng thái và phản hồi sau thao tác. ASCII wireframe dùng dữ liệu ngành spa/phòng khám thật.
SCR-01: CustomerDetail — tab Hồ sơ bệnh án
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Bác sĩ, y tá, QL CN, Admin/Ops và người có quyền xem tóm tắt hồ sơ bệnh án |
| Vào màn để quyết định gì? | Xem Hồ sơ bệnh án chính của khách, lịch sử Bệnh án lượt khám, trạng thái in/scan và cảnh báo an toàn |
| Dữ liệu chính | clinical_profile, clinical_record, clinical_form_instance, reference_file, medical_record_access_log |
| CTA chính / phụ | Primary: "Tạo lượt khám mới"; Secondary: "Tải bản scan đã ký", "Mở quyền khẩn cấp", "Xuất sổ khám" |
| Điều không được hiểu nhầm | Tab này là phần mở rộng của CustomerDetail hiện tại. 16 tab cũ giữ nguyên; tab mới chỉ hiện khi có clinical_record.view_summary |
B2.2) Bố cục — gắn vào CustomerDetail hiện tại
text
/crm/customer/{id}/clinical-record [CustomerDetail — mở rộng tab thứ 17]
┌────────────────────────────────────────────────────────────────────────────┐
│ Header KH: Lê Thị Hương · 0909 123 456 · CN gần nhất: Cao Lãnh │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ Sidebar KH │ Tabs hiện có: [Tổng quan] [Ví] [Đơn hàng] ... [16 tabs] │
│ (KEEP) │ [Hồ sơ bệnh án ★ NEW] │
│ ├─────────────────────────────────────────────────────────┤
│ Wallet, tag VIP │ ┌─ Hồ sơ bệnh án chính ──────────────────────────────┐ │
│ Lịch sử mua │ │ Mã BA chính: DVA-DL-CL-2026-00147 │ │
│ Ghi chú CRM │ │ Loại: Da liễu · CN tạo: Cao Lãnh · Tạo: 02/05/2026 │ │
│ │ │ Cảnh báo an toàn: Dị ứng Penicillin · Bệnh nền: ĐTĐ│ │
│ │ └────────────────────────────────────────────────────┘ │
│ │ │
│ │ [Tạo lượt khám mới] [Mở phiên khách tự khai] [Xuất sổ] │
│ │ │
│ │ Bộ lọc: [Từ ngày] [Đến ngày] [Trạng thái BA ▼] [Loại ▼]│
│ │ │
│ │ ┌────┬──────────┬──────────────┬────────┬────────────┐ │
│ │ │Ngày│ STT sổ │ Loại BA │ BS │ Trạng thái │ │
│ │ ├────┼──────────┼──────────────┼────────┼────────────┤ │
│ │ │02/5│ DVA-CL...│ Da liễu │ BS Hương│ Đã ký+scan│ │
│ │ │28/4│ DVA-CL...│ Thẩm mỹ │ BS Long │ Cần scan │ │
│ │ │15/4│ DVA-CL...│ Da liễu │ BS Hương│ Bản nháp │ │
│ │ └────┴──────────┴──────────────┴────────┴────────────┘ │
└──────────────────┴─────────────────────────────────────────────────────────┘B2.3) Cột và hành động trong bảng
| Cột / hành động | Hiển thị | Điều kiện |
|---|---|---|
| Ngày khám | DD/MM/YYYY HH:mm | Luôn hiện với view_summary |
| STT sổ khám / thủ thuật | visit_log_number hoặc procedure_log_number | Trống thì hiển thị "Chưa cấp số" |
| Loại BA | "Da liễu", "Thẩm mỹ" | Theo form_type |
| Bác sĩ phụ trách | Tên BS + chi nhánh | Luôn hiện với view_summary |
| Trạng thái BA | Badge theo draft/completed/printed/signed/... | Ref B2.11 LIFECYCLE-002 |
| Cảnh báo scan | "Cần scan", "Thiếu: Cam kết" | Chỉ hiện khi status='printed' hoặc checklist thiếu |
| Xem chi tiết | Mở form BA readonly/editable | Tầng 3 chỉ hiện nếu có view_medical_detail |
| Tải bản scan đã ký | Mở SCR-10 | Khi status='printed' và có upload_scan |
| Mở quyền khẩn cấp | Mở hộp thoại lý do | Chỉ khi khác CN và có emergency_override |
B2.4) Quy ước tương tác
| Tình huống | Hành vi |
|---|---|
| Khách chưa có BA | Hiển thị empty state "Khách chưa có hồ sơ bệnh án nào" + CTA "Tạo lượt khám mới" |
| Có BA khác chi nhánh | Hiển thị tầng 1+2; field tầng 3 = "—" + tooltip "Bị ẩn theo phân quyền" |
| Bấm "Mở quyền khẩn cấp" | Bắt nhập lý do ≥30 ký tự; sau xác nhận ghi medical_record_access_log; session tầng 3 hết hạn sau 1 giờ |
| Bấm "Tạo lượt khám mới" | Mở SCR-05, prefill khách hiện tại + CN hiện tại nếu user chỉ quản lý 1 CN |
| Filter trả 0 dòng | Copy: "Không có bệnh án phù hợp với bộ lọc. Vui lòng thử lại với điều kiện khác." |
B2.5) Phân quyền và trạng thái
| Quyền | UI |
|---|---|
Không có clinical_record.view_summary | Ẩn tab Hồ sơ bệnh án; route guard trả 403 |
Có view_summary, không có view_medical_detail | Thấy mã BA, trạng thái, số lượt, cảnh báo an toàn; không thấy ICD-10, ghi chú BS, form raw, ảnh, scan |
Có view_medical_detail cùng CN | Thấy tầng 3 đầy đủ theo branch scope |
| Sale | Không dùng SCR-01 để xem y tế; chuyển sang SCR-13 nếu có quyền clinical_sales.view_safe_summary |
B2.6) Variant wireframes per role (BẮT BUỘC theo permission-spec.md P10 + ui-spec template B2.2.0)
Mỗi variant render khác nhau theo
view_modetừ resolver. FE đọc response trả về, không tự suy luận.
Variant A — BS cùng CN (view_mode='full_tier3')
text
[Tab Hồ sơ bệnh án — BS cùng CN]
┌─ Hồ sơ bệnh án chính ──────────────────────────────┐
│ Mã BA: DVA-DL-CL-2026-00147 │
│ Loại: Da liễu · CN tạo: Cao Lãnh · Tạo: 02/05/2026 │
│ Cảnh báo an toàn: ⚠ Dị ứng Penicillin (NẶNG) │
│ Bệnh nền: Đái tháo đường týp 2 │
└────────────────────────────────────────────────────┘
[Tạo lượt khám mới] [Mở phiên khách tự khai] [Xuất sổ]
┌────┬──────────┬──────────────┬────────┬────────────┬──────────────┐
│Ngày│ STT │ Loại BA │ BS │ Trạng thái │ Chẩn đoán │
├────┼──────────┼──────────────┼────────┼────────────┼──────────────┤
│02/5│DVA-CL...│ Da liễu │BS Hương│ Đã ký+scan │ L70.0 + L73.2│ ← TẦNG 3 hiện
│28/4│DVA-CL...│ Thẩm mỹ │BS Long │ Cần scan │ Q67.4 │
│15/4│DVA-CL...│ Da liễu │BS Hương│ Bản nháp │ (chưa nhập) │
└────┴──────────┴──────────────┴────────┴────────────┴──────────────┘
Row action: [Xem BA] [Tải bản scan đã ký] [In lại]Field allowlist: mọi field theo permission-spec.md P10 (full_tier3)
Variant B — BS khác CN (view_mode='summary', không emergency)
text
[Tab Hồ sơ bệnh án — BS CN khác]
┌─ Hồ sơ bệnh án chính ──────────────────────────────┐
│ Mã BA: DVA-DL-CL-2026-00147 │
│ Loại: Da liễu · CN tạo: Cao Lãnh │
│ Cảnh báo an toàn: ⚠ Có dị ứng — chuyển BS │ ← chỉ level/code
└────────────────────────────────────────────────────┘
⚠ Bạn không thuộc CN tạo. Tầng 3 (chẩn đoán, đơn thuốc, ảnh y tế)
bị ẩn theo phân quyền. Mở quyền khẩn cấp nếu là tình huống cấp cứu.
[Mở quyền khẩn cấp] [Tạo lượt khám mới] (CN hiện tại)
┌────┬──────────┬──────────────┬────────┬────────────┬──────────────┐
│Ngày│ STT │ Loại BA │ BS │ Trạng thái │ Chẩn đoán │
├────┼──────────┼──────────────┼────────┼────────────┼──────────────┤
│02/5│DVA-CL...│ Da liễu │BS Hương│ Đã ký+scan │ — │ ← TẦNG 3 ẩn
│28/4│DVA-CL...│ Thẩm mỹ │BS Long │ Cần scan │ — │
└────┴──────────┴──────────────┴────────┴────────────┴──────────────┘
Row action: [Xem tóm tắt] (no [Xem BA full])Field allowlist: chỉ tầng 1+2 — id, profile_code, visit_log_number, status, form_type, primary_doctor_id, created_at, branch_id, allergy_summary (level only); ICD/diagnosis/form_data omit.
Variant C — Y tá cùng CN (view_mode='admin_shared')
text
[Tab Hồ sơ bệnh án — Y tá]
┌─ Hồ sơ bệnh án chính ──────────────────────────────┐
│ Mã BA: DVA-DL-CL-2026-00147 │
│ Cảnh báo an toàn: ⚠ Dị ứng Penicillin (NẶNG) │
│ Bệnh nền: Đái tháo đường týp 2 │
└────────────────────────────────────────────────────┘
[Tạo lượt khám mới] [Mở phiên khách tự khai]
(KHÔNG có [Xuất sổ])
┌────┬──────────┬──────────────┬────────┬────────────┬──────────┐
│Ngày│ STT │ Loại BA │ BS │ Trạng thái │ Scan │
├────┼──────────┼──────────────┼────────┼────────────┼──────────┤
│02/5│DVA-CL...│ Da liễu │BS Hương│ Cần scan │ Thiếu 2 │ ← Y tá thấy việc cần scan
│28/4│DVA-CL...│ Thẩm mỹ │BS Long │ Đã in │ — │
└────┴──────────┴──────────────┴────────┴────────────┴──────────┘
Row action: [Tải bản scan đã ký] [Mở phiếu hành chính]
(no [Sửa chẩn đoán])Field allowlist: tầng 1+2 + phần hành chính của form_data (admin_shared); chẩn đoán/y lệnh ẩn.
Variant D — Sale CRM (chuyển sang SCR-13)
text
[Tab Hồ sơ bệnh án] (Sale CRM portal)
⛔ Bạn không có quyền xem nội dung y tế.
Vui lòng dùng [Trang xem an toàn (Sale)] để tư vấn KH.
[Đến Trang xem an toàn (Sale) →]Field allowlist: không có gì — Sale bị hard-deny tầng 3 (permission-spec.md P1.3). Hiển thị banner redirect, không list BA.
Variant E — User không có view_summary (Lễ tân, role chưa được cấp)
text
(Tab Hồ sơ bệnh án không hiển thị trong Customer Detail)Behavior: route guard tại Customer Detail không render tab; nếu user gõ URL /crm/customer/:id/clinical-record trực tiếp → 403 + redirect về /crm/customer/:id với toast "Bạn không có quyền xem mục này".
Variant F — Loading + Error + Empty
| State | UI |
|---|---|
| Loading | Skeleton 5 dòng + spinner header card "Hồ sơ bệnh án chính"; CTA disabled |
| Error tải dữ liệu | Banner đỏ "Không thể tải hồ sơ bệnh án. Vui lòng thử lại." + nút [Thử lại] |
| Empty (KH chưa có BA) | Card header "Khách chưa có hồ sơ bệnh án" + CTA [Tạo lượt khám mới] + hint "Tạo lượt khám đầu tiên cho khách này" |
Variant G — Emergency override active (view_mode='full_tier3' tạm thời)
Như Variant A nhưng có badge:
text
🚨 PHIÊN KHẨN CẤP CÒN 0:42:18 [Đóng phiên]
Lý do: "Khách cấp cứu chuyển từ TBII, cần xem chẩn đoán cũ"
Mọi thao tác sẽ được ghi audit log.
(... bên dưới giống Variant A)Tổng: 7 variant cho SCR-01. FE phải implement đủ; QA test TC-PERM-MASK-01..05 + TC-PERM-EO-01..08 verify từng variant.
SCR-02: OrderForm — cảnh báo dịch vụ cần bệnh án
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Lễ tân/POS khi tạo đơn dịch vụ |
| Vào màn để quyết định gì? | Biết dịch vụ nào cần Bệnh án lượt khám trước khi thực hiện, tránh bán dịch vụ xâm lấn mà không tạo BA |
| Dữ liệu chính | order_item.product_id, service_clinical_classification.classification_status, technical_category, appointment.reference_appointment_id |
| CTA chính / phụ | Primary: "Tạo đơn"; Secondary: "Tạo lượt khám", "Xem dịch vụ cần BA" |
| Điều không được hiểu nhầm | unclassified không được hiểu là "không cần BA"; phải chặn hoặc yêu cầu QL CN phân loại trước khi hoàn tất |
B2.2) Bố cục — mở rộng bước Dịch vụ trong OrderForm
text
/e/service-order/orders/create [OrderForm bước 1 — Dịch vụ]
┌─ Bước 1/4: Chọn dịch vụ ─────────────────────────────────────────────┐
│ KH: Lê Thị Hương · CN: Cao Lãnh │
│ │
│ Dịch vụ đã chọn: │
│ ┌──────────────────────────┬─────────┬──────────────┬──────────────┐ │
│ │ Dịch vụ │ Số tiền │ Phân loại BA │ Thao tác │ │
│ ├──────────────────────────┼─────────┼──────────────┼──────────────┤ │
│ │ Liệu trình trị mụn 5 buổi│3.500.000đ│ Cần BA │ [Tạo lượt khám]│ │
│ │ Tư vấn miễn phí │0đ │ Không cần BA │ — │ │
│ │ Laser CO2 mới │2.800.000đ│ Chưa phân loại│ [Đến danh mục dịch vụ →]│
│ └──────────────────────────┴─────────┴──────────────┴──────────────┘ │
│ │
│ ⚠ Có 1 dịch vụ cần bệnh án trước khi thực hiện. │
│ Vui lòng tạo lượt khám hoặc gắn với lượt khám đã có. │
│ │
│ ⛔ Có 1 dịch vụ chưa phân loại. Không thể hoàn tất đơn cho tới khi │
│ QL CN/Admin phân loại dịch vụ — kỹ thuật. │
│ │
│ [Quay lại] [Tiếp] (bị khóa) │
└──────────────────────────────────────────────────────────────────────┘B2.3) Quy tắc hiển thị cảnh báo
| Classification | Badge | Hành vi |
|---|---|---|
mapped_requires_ba | "Cần BA" | Hiện banner vàng; nếu chưa có lượt khám phù hợp thì hiện CTA "Tạo lượt khám" |
explicitly_no_ba | "Không cần BA" | Không cảnh báo |
unclassified | "Chưa phân loại" | Banner đỏ; khóa nút "Tiếp"; deeplink đến SCR-04d nếu user có quyền cấu hình |
| Không có module PK tại CN | Không hiện badge BA | OrderForm giữ nguyên như hiện tại |
B2.4) Quy ước tương tác
| Tình huống | Hành vi |
|---|---|
| Một đơn có nhiều dịch vụ cần BA | Gom 1 banner, liệt kê tên dịch vụ; không lặp nhiều banner |
| Dịch vụ cần BA đã có appointment phù hợp trong ngày | CTA đổi thành "Gắn lượt khám đã có" |
| Tạo lượt khám từ đơn | Mở SCR-05, prefill KH, CN, danh sách dịch vụ và order_item_id nếu đã có |
| User không có quyền tạo lượt khám | CTA ẩn; banner vẫn nói "Vui lòng chuyển bác sĩ/lễ tân có quyền tạo lượt khám" |
| Lưu đơn nháp | Cho lưu nháp, nhưng không cho chuyển trạng thái thực hiện dịch vụ nếu còn unclassified |
B2.5) Copy bắt buộc
| Tình huống | Copy |
|---|---|
| Có dịch vụ cần BA | "Có {N} dịch vụ cần bệnh án trước khi thực hiện." |
| Chưa phân loại | "Dịch vụ chưa phân loại. Vui lòng phân loại dịch vụ — kỹ thuật trước khi hoàn tất đơn." |
| Không có quyền | "Bạn không có quyền tạo lượt khám. Vui lòng chuyển cho lễ tân hoặc bác sĩ phụ trách." |
SCR-03: AppointmentForm — khách walk-in và badge bệnh án
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Lễ tân, y tá, bác sĩ trực quầy |
| Vào màn để quyết định gì? | Tạo lượt khám cho khách có lịch hoặc khách walk-in; nhìn nhanh lịch hẹn nào đã có/thiếu BA |
| Dữ liệu chính | appointment, appointment.customer_id, appointment.order_item_id, clinical_record.status, order.reference_appointment_id |
| CTA chính / phụ | Primary: "Lưu lịch hẹn"; Secondary: "Tạo lượt khám", "Tạo khách mới", "Gắn đơn sau" |
| Điều không được hiểu nhầm | Walk-in hợp lệ chỉ ở order_item_id=NULL. customer_id BẮT BUỘC có (theo schema dev-spec): nếu KH chưa có hồ sơ thì lễ tân tạo KH mới inline trước khi lưu lượt khám. Backend null-guard order_item_id, không tạo đơn giả |
B2.2) Form tạo/sửa lịch hẹn
text
[Tạo lịch hẹn / lượt khám] [×]
CN: [Cao Lãnh ▼] Ngày giờ: [02/05/2026 14:30]
☑ Khách walk-in
├─ KH đã có hồ sơ? [Tìm SĐT / tên khách...]
└─ Chưa có hồ sơ? [+ Tạo khách mới ngay] (mở popup tạo KH inline)
Sau khi tạo xong, hệ thống tự gắn `customer_id` mới vào lịch hẹn.
Dịch vụ dự kiến: [Liệu trình trị mụn 5 buổi ▼] Badge: [Cần BA]
Bác sĩ phụ trách: [BS Trần Mỹ Hương ▼]
Ghi chú quầy: [Khách đến trực tiếp, khám trước rồi quyết định dịch vụ]
⚠ Lượt khám walk-in chưa cần đơn hàng. Sau khi bác sĩ khám xong, lễ tân có thể
tạo đơn và gắn `reference_appointment_id` vào lượt khám này.
[Hủy] [Lưu lịch hẹn]B2.3) Danh sách lịch hẹn — badge bệnh án
text
/e/service-order/appointment
[Ngày: 02/05/2026] [CN: Cao Lãnh] [Trạng thái BA: Tất cả ▼] [Walk-in: Tất cả ▼]
┌──────┬──────────────┬──────────────┬──────────────┬────────────┬─────────────────────┐
│ Giờ │ Khách │ Dịch vụ │ Bác sĩ │ BA │ Thao tác │
├──────┼──────────────┼──────────────┼──────────────┼────────────┼─────────────────────┤
│09:00 │ Nguyễn Lan │ Nâng mũi │ BS Long │ Cần BA │ [Tạo BA] │
│10:30 │ Trần Hà (mới)│ Tư vấn │ BS Hương │ Không cần │ [Mở] [Tạo đơn] │
│14:30 │ Lê Hương │ Trị mụn │ BS Hương │ Đã có BA │ [Xem BA] [Tạo đơn] │
│15:00 │ Phạm Hà │ Laser CO2 │ BS Hương │ BA nháp │ [Mở nháp] │
└──────┴──────────────┴──────────────┴──────────────┴────────────┴─────────────────────┘Ghi chú: với lịch walk-in chưa có đơn (
appointment.order_item_id=NULL), CTA[Tạo đơn]chỉ hiện sau khi BS hoàn thành BA hoặc xác nhận xong dịch vụ; tạo đơn →order.reference_appointment_idlink muộn (DEC-003), không backfillappointment.order_item_id.
B2.4) Quy tắc badge
| Badge | Điều kiện |
|---|---|
| "Không cần BA" | Tất cả dịch vụ trong lịch hẹn là explicitly_no_ba |
| "Cần BA" | Có ít nhất 1 dịch vụ mapped_requires_ba và chưa có clinical_record |
| "BA nháp" | Có clinical_record.status='draft' |
| "Đã có BA" | Có completed/printed/signed |
| "Cần scan" | Có status='printed' nhưng checklist scan chưa đủ |
| "Chưa phân loại" | Có dịch vụ unclassified; ưu tiên hiển thị cao nhất |
B2.5) Null guard UI
| Trường hợp | Hành vi |
|---|---|
customer_id=NULL | Không xảy ra ở Day-1 — schema yêu cầu clinical_*.customer_id NOT NULL. UI buộc tạo KH mới inline trước khi lưu lượt khám. Nếu legacy data còn dòng customer_id=NULL, danh sách hiển thị "Hồ sơ KH chưa rõ — bổ sung trước khi in BA" và chặn CTA "Tạo BA"/"In bộ hồ sơ" |
order_item_id=NULL | Hiển thị "Chưa gắn đơn"; CTA "Tạo đơn từ lượt khám" hiện sau khi BS hoàn thành BA |
reference_appointment_id đã gắn | Hiển thị mã đơn liên quan; không backfill appointment.order_item_id (DEC-003) |
| CN không bật module PK | Không hiện badge BA; AppointmentForm giữ nguyên hành vi cũ |
SCR-04: BranchDetail — tab Phòng khám (5 bước cấu hình)
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Admin/Ops cấu hình; QL CN xem readonly; Lễ tân/Y tá không thấy tab |
| Vào màn để quyết định gì? | Bật module Phòng khám cho CN, đi qua 5 bước cấu hình + 1 bước kiểm tra sẵn sàng, đạt 100% rồi phát hành |
| Dữ liệu chính | branch.features.clinic_enabled, clinic_module_publication, branch_technical_config, technical_category, service_clinical_classification |
| CTA chính / phụ | Primary: "Phát hành" (chỉ mở khi kiểm tra sẵn sàng đạt 100%); Secondary: "Lưu nháp", "Tạm dừng" (nếu đang hoạt động) |
| Điều không được hiểu nhầm | Wizard hoàn tất ≠ đang hoạt động; phải bấm "Phát hành" + chọn effective_at |
B2.2) Bố cục — Demo gắn vào UI hiện tại (Mở rộng)
text
/s/internal-settings/branch/{id} [Trang chi nhánh — mở rộng tab thứ 4]
┌─────────────────────────────────────────────────────────────────────────┐
│ Header: CN Cao Lãnh [Lưu] [Hủy] │
├──────────────────┬──────────────────────────────────────────────────────┤
│ BranchInfo │ Tabs: [Bộ phận] [Kho] [Dịch vụ] [Phòng khám ★ NEW] │
│ (KEEP — sidebar) ├──────────────────────────────────────────────────────┤
│ │ >>> KHU VỰC TAB MỚI "PHÒNG KHÁM" <<< │
│ Mã: CL │ │
│ Tỉnh: Đồng Tháp │ ┌─ Trạng thái: [Đang cấu hình `setup_draft`] ┐ │
│ Loại: Spa+PK │ │ │ │
│ │ │ ┌── Trợ lý cấu hình phòng khám (6 bước) ────────┐ │ │
│ [Sửa] │ │ │ ●━━●━━●━━○━━○━━○ │ │ │
│ │ │ │ 1 2 3 4 5 6 │ │ │
│ │ │ │ Loại Giấy Danh Phân Phân Kiểm tra │ │ │
│ │ │ │ PK phép mục loại quyền sẵn sàng │ │ │
│ │ │ │ KT DV ↔ KT │ │ │
│ │ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ │ Bước hiện tại: 3 — Danh mục kỹ thuật │ │
│ │ │ (nội dung bước hiện tại) │ │
│ │ │ │ │
│ │ │ [Quay lại] [Lưu nháp] [Tiếp] │ │
│ │ └──────────────────────────────────────────────────┘ │
└──────────────────┴──────────────────────────────────────────────────────┘B2.3) Phân loại reuse + điểm update
| Phân loại | File hiện có | Vị trí update | Lý do vị trí |
|---|---|---|---|
| 🔧 Mở rộng | user/pages/BranchDetail.tsx | Thêm tab thứ 4 sau tab "Dịch vụ" | Khớp UX hiện tại 3 tabs; thêm tab Phòng khám đứng cuối logic vận hành |
B2.4) Quy ước field/CTA mới (ref B0.4 — không lặp)
Field thay đổi ref dòng B0.4: branch.features.clinic_enabled, clinic_module_publication.status. CTA Phát hành chỉ mở khi readiness_snapshot đạt 100% R-01..R-10.
B2.5) Bộ lọc — N/A (cấu hình per CN, không có bộ lọc)
B2.6) Bảng nội dung chính — N/A (trợ lý cấu hình theo bước, không phải bảng dữ liệu)
B2.7) Quy ước tương tác
| Tình huống | Hành vi |
|---|---|
| Chế độ lưu | Lưu thủ công + Lưu nháp |
| Có thay đổi chưa lưu | Dấu (•) ở tiêu đề tab + chặn chuyển trang |
| Tìm kiếm/bộ lọc | N/A |
| Reset dây chuyền | Đổi loại PK ở bước 1 → reset bước 3 (KT) + bước 4 (DV ↔ KT) với hộp thoại xác nhận |
| Cập nhật bất đồng bộ | Theo lối thận trọng — chờ phản hồi trước khi sang bước tiếp theo |
| Tác vụ chạy lâu | Kiểm tra sẵn sàng (R-01..R-10) hiện lớp chờ phủ toàn bước |
B2.8) Ma trận phân quyền — ref B6 ma trận canonical mục clinic_module
B2.9) Ma trận trạng thái — ref B0.5 dòng SCR-04
B2.10) Phản hồi sau thao tác
| Hành động | Phản hồi UI | Copy mẫu |
|---|---|---|
| Lưu nháp thành công | Thông báo nhanh | "Đã lưu nháp lúc 14:32" |
| Tiếp bước (validation đạt) | Chuyển bước + cuộn lên đầu | (không thông báo) |
| Tiếp bước (validation lỗi) | Lỗi tại field + banner top | "Vui lòng hoàn thành các mục bắt buộc trước khi tiếp tục" |
| Phát hành thành công | Thông báo nhanh + chuyển sang trạng thái mới | "Đã phát hành module Phòng khám CN Cao Lãnh, áp dụng từ 02/05/2026 09:00" |
| Tạm dừng | Hộp thoại xác nhận | "Tạm dừng module Phòng khám CN Cao Lãnh? Bệnh án mới sẽ không tạo được. Bệnh án cũ vẫn xem được." |
B2.11) Mapping UI theo vòng đời (LIFECYCLE-001)
| Trạng thái | CTA hiển thị | CTA ẩn/khóa | Field sửa được | Badge |
|---|---|---|---|---|
Tắt (off) | "Bật module" | — | (chưa cấu hình) | "Tắt" (xám) |
Đang cấu hình (setup_draft) | "Lưu nháp", "Tiếp", "Quay lại" | "Phát hành" bị khóa | 5 bước cấu hình của trợ lý | "Đang cấu hình" (vàng) |
Đã sẵn sàng (ready_to_publish) | "Phát hành", "Sửa cấu hình" | — | Chỉ đọc trong trợ lý cấu hình | "Đã sẵn sàng" (xanh nhạt) |
Đã lập lịch (scheduled) | "Hủy lập lịch" | "Phát hành" ẩn | Readonly | "Đã lập lịch DD/MM/YYYY HH:mm" (xanh) |
Đang hoạt động (live) | "Tạm dừng", "Sửa cấu hình" | "Phát hành" ẩn | Chỉ đọc; chỉ Admin/Ops sửa được trong tab con cấu hình | "Đang hoạt động" (xanh đậm) |
Đã tạm dừng (paused) | "Tiếp tục" (→ live), "Sửa cấu hình" (→ setup_draft/ready_to_publish qua re-check) | "Phát hành" ẩn | Chỉ đọc; Admin/Ops sửa được | "Đã tạm dừng" (đỏ nhạt) + lý do |
SCR-04a: Bước 1 — Loại phòng khám
Mục tiêu: Admin/Ops chọn loại phòng khám của chi nhánh để hệ thống biết cần bật BA Da liễu, BA Thẩm mỹ hay cả hai.
text
[Bước 1/6 — Loại phòng khám] CN Cao Lãnh
Chi nhánh này có vận hành phòng khám nào?
( ) Chỉ Da liễu
Dùng Bệnh án Da liễu, sổ khám bệnh, phiếu dị ứng, đơn thuốc.
( ) Chỉ Phẫu thuật Thẩm mỹ
Dùng Bệnh án Thẩm mỹ, sổ khám bệnh, sổ thủ thuật, phiếu theo dõi điều trị.
(●) Cả Da liễu + Phẫu thuật Thẩm mỹ
Dùng cả 2 loại bệnh án. Dịch vụ sẽ được phân loại theo từng kỹ thuật.
Header in phiếu:
[PHÒNG KHÁM CHUYÊN KHOA DA LIỄU DIVA CAO LÃNH ]
Người phụ trách y khoa:
[BS Trần Mỹ Hương ▼] Số điện thoại hỗ trợ: [0909 000 111]
[Quay lại] [Lưu nháp] [Tiếp]| Field | Validation | Hành vi |
|---|---|---|
| Loại phòng khám | Bắt buộc 1 lựa chọn | Đổi loại sau khi đã cấu hình bước 3/4 phải confirm reset dây chuyền |
| Header in phiếu | Bắt buộc, tối đa 200 ký tự | Dùng cho PDF/in bộ hồ sơ |
| Người phụ trách y khoa | Bắt buộc trước phát hành | Dùng trong kiểm tra sẵn sàng R-09 |
| SĐT hỗ trợ | 10 chữ số, bắt đầu bằng 0 | Hiện trong runbook nội bộ, không in lên BA nếu Legal không duyệt |
Copy lỗi: "Vui lòng chọn loại phòng khám trước khi tiếp tục."
SCR-04b: Bước 2 — Giấy phép và thông tin pháp lý
Mục tiêu: nhập giấy phép phòng khám để in đúng header, kiểm soát hạn giấy phép và chặn phát hành khi thiếu artifact pháp lý.
text
[Bước 2/6 — Giấy phép phòng khám] CN Cao Lãnh
Số giấy phép: [123/SYT-DT ] *
Cơ quan cấp: [Sở Y tế Đồng Tháp ] *
Ngày cấp: [15/02/2024] Ngày hết hạn: [15/02/2029] *
Địa chỉ hành nghề: [12 Lê Lợi, Phường 1, TP. Cao Lãnh ] *
File giấy phép:
┌─────────────────────────────────────────────────────────────────────┐
│ Kéo-thả file PDF/JPG/PNG hoặc [Chọn file] │
│ Đã tải: giay-phep-cao-lanh.pdf · 1.4MB · ✓ │
└─────────────────────────────────────────────────────────────────────┘
☐ Legal đã xác nhận mẫu giấy + lưu trữ + scan reference cho pilot
☐ QL CN đã kiểm tra máy in, máy scan và tài khoản tải file
[Quay lại] [Lưu nháp] [Tiếp]| Field | Validation | Hành vi |
|---|---|---|
| Số giấy phép | Bắt buộc, không trùng trong CN đang hoạt động | Trùng thì hiển thị "Số giấy phép đã tồn tại ở chi nhánh khác" |
| Ngày hết hạn | Phải lớn hơn ngày hiện tại khi phát hành | Hết hạn trong 30 ngày → cảnh báo vàng |
| File giấy phép | PDF/JPG/PNG, tối đa 20MB | Thiếu file → R-02 không đạt |
| Legal xác nhận | Checkbox bắt buộc trước go-live, chưa bắt buộc để lưu nháp | Dùng cho R-10 |
Trạng thái đặc biệt: giấy phép hết hạn sau khi CN đã live không tự pause module. Trang điều phối SCR-16 phải báo "Giấy phép hết hạn" và yêu cầu Ops xử lý.
SCR-04c: Bước 3 — Danh mục kỹ thuật
Mục tiêu: chọn Danh mục kỹ thuật (technical_category) được phép dùng tại chi nhánh, gắn mức rủi ro dị ứng và làm nguồn cho bước phân loại dịch vụ — kỹ thuật.
text
[Bước 3/6 — Danh mục kỹ thuật] CN Cao Lãnh
[Tìm kỹ thuật...] [Loại PK: Tất cả ▼] [Rủi ro dị ứng: Tất cả ▼]
[+ Thêm kỹ thuật nội bộ] [Import từ danh mục master]
┌────┬──────────────────────────┬──────────┬──────────────┬─────────────┬──────────────┐
│ # │ Kỹ thuật │ Loại PK │ Rủi ro dị ứng │ Sử dụng tại │ Sẵn sàng │
│ │ │ │ │ CN │ phát hành │
├────┼──────────────────────────┼──────────┼──────────────┼─────────────┼──────────────┤
│ 1 │ Áp lạnh nitơ │ Da liễu │ Thấp │ Đang dùng │ ✓ │
│ 2 │ Tiêm filler │ Thẩm mỹ │ Cao │ Đang dùng │ ✓ │
│ 3 │ Laser CO2 Fractional │ Da liễu │ Chưa phân loại│ Đang dùng │ ⚠ Chặn R-04 │
│ 4 │ Nâng mũi cấu trúc │ Thẩm mỹ │ Cao │ Đang dùng │ ✓ │
│ 5 │ Tiêm meso (cũ) │ Da liễu │ Trung bình │ Tạm ngưng │ — (không dùng)│
└────┴──────────────────────────┴──────────┴──────────────┴─────────────┴──────────────┘
⚠ Còn 1 kỹ thuật đang dùng nhưng chưa phân loại rủi ro dị ứng. Bước kiểm
tra sẵn sàng R-04 sẽ không đạt cho tới khi Medical Lead phân loại.
[Quay lại] [Lưu nháp] [Tiếp]| Field | Validation | Hành vi |
|---|---|---|
| Tên kỹ thuật | Bắt buộc, không trùng trong cùng CN | Cho phép cùng tên ở CN khác nếu master khác |
| Loại PK | DL, TM, both | Lọc theo loại phòng khám ở bước 1 |
allergy_risk_level | unknown/low/medium/high | unknown chặn phát hành và chặn hoàn thành BA nếu KT được dùng |
| Trạng thái sử dụng | Đang dùng / Tạm ngưng | Tạm ngưng không hiện ở bước 4 |
Quy tắc import: import không ghi đè kỹ thuật đã sửa tại CN. Nếu trùng tên, UI hiện hộp thoại so sánh "Giữ bản CN" / "Cập nhật từ master".
SCR-04d: Phân loại dịch vụ — kỹ thuật
B2.2) Wireframe
text
[Bước 4/6 — Phân loại dịch vụ — kỹ thuật] CN Cao Lãnh
Hiện trạng: 50 dịch vụ đang bán ✓ 45 đã phân loại ⚠ 5 chưa phân loại
[Tìm kiếm dịch vụ...] [Lọc: Tất cả ▼] [Lọc trạng thái: Tất cả ▼]
┌────┬──────────────────────────────┬─────────────────────────┬──────────────┐
│ # │ Dịch vụ │ Phân loại │ Kỹ thuật │
├────┼──────────────────────────────┼─────────────────────────┼──────────────┤
│ 1 │ Liệu trình trị mụn 5 buổi │ ◉ Cần BA ○ Không cần │ [Áp lạnh ▼] │
│ │ (3.500.000đ) │ ○ Chưa phân loại │ │
├────┼──────────────────────────────┼─────────────────────────┼──────────────┤
│ 2 │ Filler Hyaluronic 1ml │ ◉ Cần BA │ [Tiêm filler]│
│ │ (4.200.000đ) │ │ │
├────┼──────────────────────────────┼─────────────────────────┼──────────────┤
│ 3 │ Tư vấn miễn phí │ ○ Cần BA ◉ Không cần BA │ — │
│ │ (0đ) │ │ │
├────┼──────────────────────────────┼─────────────────────────┼──────────────┤
│ 4 │ Laser CO2 mới │ ○ Cần BA ○ Không cần │ — │
│ │ (2.800.000đ) │ ◉ Chưa phân loại │ ⚠ Bắt phân │
│ │ │ │ loại trước│
└────┴──────────────────────────────┴─────────────────────────┴──────────────┘
⚠ Còn 5 dịch vụ chưa phân loại. Bắt buộc phân loại 100% trước khi tiếp.
[Quay lại] [Lưu nháp] [Tiếp →] (bị khóa)B2.4) Quy ước field — ref B0.4 dòng service_clinical_classification.classification_status
B2.7) Quy ước tương tác
| Tình huống | Hành vi |
|---|---|
| Đổi phân loại 1 dòng | Tự lưu ngay trên dòng sau 500ms |
Còn unclassified | "Tiếp" bị khóa + banner đỏ |
| Đổi loại PK ở bước 1 | Hộp thoại xác nhận "Đổi loại PK sẽ xóa phân loại hiện có. Tiếp tục?" |
SCR-04e: Bước 5 — Phân quyền phòng khám
Mục tiêu: Admin/Ops cấp quyền vận hành tối thiểu cho chi nhánh trước khi phát hành. Vai trò chỉ là mẫu seed; quyền thực tế đọc từ Permission v2.
text
[Bước 5/6 — Phân quyền phòng khám] CN Cao Lãnh
Nhóm vận hành bắt buộc:
┌──────────────────┬──────────────────────────────┬──────────────┬───────────┐
│ Nhóm │ Nhân sự │ Quyền chính │ Trạng thái │
├──────────────────┼──────────────────────────────┼──────────────┼───────────┤
│ Bác sĩ │ BS Trần Mỹ Hương, BS Phát │ Xem/sửa tầng 3│ Đủ │
│ Y tá │ Y tá Hà │ Hành chính + scan│ Đủ │
│ QL chi nhánh │ Chị Tâm │ Sổ, chốt ngày│ Đủ │
│ Lễ tân │ Mai │ Tạo lượt khám│ Đủ │
│ Ops hỗ trợ D0 │ Chưa chọn │ Điều phối │ Thiếu │
└──────────────────┴──────────────────────────────┴──────────────┴───────────┘
Quyền nhạy cảm:
☑ Bác sĩ cùng CN được `clinical_record.view_medical_detail`
☐ QL CN được xem tầng 3 (không khuyến nghị Day-1)
☑ Y tá được `upload_scan` + `edit_admin_shared`
☑ Sale chỉ dùng Trang xem an toàn (Sale), không xem tầng 3
[Thêm nhân sự] [Xem ma trận quyền] [Lưu nháp] [Tiếp]| Nhóm | Quyền tối thiểu | Cảnh báo nếu thiếu |
|---|---|---|
| Bác sĩ | doctor_workbench.access, clinical_record.view_summary, clinical_record.view_medical_detail, edit_medical_form, print | "Chưa có bác sĩ được phân quyền. Không thể phát hành." |
| Y tá | clinical_record.view_summary, edit_admin_shared, upload_scan | "Chưa có người tải bản scan đã ký." |
| QL CN | clinical_record.export_visit_log, clinic_daily_close.close_branch_day, clinic_ops.view_branch_dashboard | "Chưa có người chốt ngày phòng khám." |
| Lễ tân | clinical_record.view_summary, customer_clinical_intake.open_session | "Chưa có người mở phiếu khách tự khai." |
| Ops | clinic_ops.view_all_dashboard, clinic_module.configure | "Chưa có người phụ trách hỗ trợ D0." |
Quy tắc UI: không khóa menu theo tên vai trò. FE chỉ dựa vào module_permission_action và globalStore.hasPermission(...); BE vẫn kiểm tra lại.
SCR-04f: Bước 6 — Kiểm tra sẵn sàng và phát hành
Mục tiêu: chạy 10 kiểm tra sẵn sàng, cho Admin xem trước tác động khi áp dụng, rồi phát hành module theo effective_at.
text
[Bước 6/6 — Kiểm tra sẵn sàng] CN Cao Lãnh
Tiến độ: 8/10 đạt
┌────┬─────────────────────────────────────────────┬──────────┬──────────────┐
│ Mã │ Kiểm tra │ Kết quả │ Thao tác │
├────┼─────────────────────────────────────────────┼──────────┼──────────────┤
│R-01│ Đã chọn loại phòng khám │ Đạt │ — │
│R-02│ Giấy phép còn hạn + file đã tải │ Đạt │ Xem file │
│R-03│ Danh mục kỹ thuật đủ cho CN │ Đạt │ Mở bước 3 │
│R-04│ Không còn kỹ thuật allergy `unknown` │ Không đạt│ Mở bước 3 │
│R-05│ 100% dịch vụ đang bán đã phân loại │ Không đạt│ Mở bước 4 │
│R-06│ Phân quyền BS/Y tá/QL CN đủ │ Đạt │ Mở bước 5 │
│R-07│ In thử PDF thành công │ Đạt │ Xem PDF │
│R-08│ BA demo tạo/in/scan trên staging đạt │ Đạt │ Xem log │
│R-09│ Đã chọn người phụ trách hỗ trợ D0 │ Đạt │ — │
│R-10│ Legal/SYT/máy scan/máy in/tài khoản upload │ Đạt │ Xem tài liệu │
└────┴─────────────────────────────────────────────┴──────────┴──────────────┘
⛔ Chưa thể phát hành. Còn 2 kiểm tra chưa đạt.
[Chạy lại kiểm tra] [Phát hành] (bị khóa)Hộp thoại phát hành khi 10/10 đạt
text
[Phát hành module Phòng khám — CN Cao Lãnh] [×]
Xem trước tác động khi áp dụng:
• 50 dịch vụ đang bán: 45 cần BA, 5 không cần BA
• 12 người dùng sẽ thấy menu/màn Phòng khám
• 2 bác sĩ được xem tầng 3 tại CN Cao Lãnh
• 7 thông báo phòng khám sẽ được bật
• Giờ chốt ngày: 20:00 Asia/Ho_Chi_Minh
Áp dụng từ:
(●) Phát hành ngay
( ) Lập lịch: [02/05/2026 09:00]
Lý do phát hành:
[Pilot Cao Lãnh theo kế hoạch đã được Legal/Ops xác nhận ]
[Hủy] [Xác nhận phát hành]| Trạng thái kiểm tra | UI | Kết quả |
|---|---|---|
| 10/10 đạt | CTA "Phát hành" mở | clinic_module_publication.status='ready_to_publish' |
| Có R-xx không đạt | CTA khóa | Không tạo lịch phát hành |
| Phát hành ngay | Confirm → status='live' nếu effective_at<=now() | UI clinical mở ngay sau refetch quyền |
| Lập lịch | status='scheduled' | UI clinical chưa mở trước effective_at |
| Tạm dừng sau live | Bắt lý do | status='paused', BA cũ readonly, không tạo BA mới |
SCR-05: Tạo lượt khám
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Lễ tân, bác sĩ, y tá được quyền tạo lượt khám |
| Vào màn để quyết định gì? | Tạo appointment/lượt khám đúng nghĩa cho khách có đơn, có lịch hoặc walk-in |
| Dữ liệu chính | appointment, customer_id, branch_id, doctor_id, order_item_id, form_type, clinical_record |
| CTA chính / phụ | Primary: "Lưu lượt khám"; Secondary: "Tạo khách mới", "Gắn đơn sau", "Mở phiếu khách tự khai" |
| Điều không được hiểu nhầm | Tạo lượt khám không đồng nghĩa đã có Bệnh án lượt khám; bệnh án sinh theo dịch vụ cần BA và form_type. customer_id luôn bắt buộc; nếu KH walk-in chưa có hồ sơ, lễ tân tạo KH mới inline trước khi lưu lượt khám |
B2.2) Popup
text
[Tạo lượt khám] [×]
CN: [Cao Lãnh ▼] Ngày giờ: [02/05/2026 14:30]
Bác sĩ phụ trách: [BS Trần Mỹ Hương ▼]
Khách hàng (bắt buộc):
(●) Khách đã có hồ sơ [Lê Thị Hương · 0909 123 456 ▼]
( ) Khách walk-in — tạo mới [+ Tạo khách mới ngay]
(mở popup tạo KH inline; sau khi lưu sẽ tự gắn `customer_id`)
Dịch vụ liên quan:
☑ Liệu trình trị mụn 5 buổi Badge: Cần BA Loại BA: [Da liễu ▼]
☐ Tư vấn miễn phí Badge: Không cần BA
Đơn hàng:
( ) Gắn với đơn hiện có: [Chọn đơn/order item ▼]
(●) Chưa có đơn, tạo sau khi bác sĩ khám
Ghi chú quầy:
[Khách đến trực tiếp, mong muốn kiểm tra mụn viêm trước khi mua liệu trình]
[Hủy] [Lưu lượt khám]B2.3) Validation và kết quả
| Trường hợp | Validation | Kết quả |
|---|---|---|
| Khách đã có hồ sơ | Bắt buộc chọn customer_id | Tạo appointment.customer_id |
| Khách walk-in chưa có hồ sơ | Buộc tạo KH mới inline trước khi lưu (customer_id không được rỗng) | Sau khi tạo KH xong, popup quay lại trạng thái đã chọn customer_id mới |
| Chưa có đơn | Cho phép order_item_id=NULL | Sau khám có CTA "Tạo đơn từ lượt khám này" |
| Dịch vụ cần BA | Bắt buộc chọn form_type | Tạo việc need_record cho Bàn việc bác sĩ |
Dịch vụ unclassified | Chặn lưu | Copy: "Dịch vụ chưa phân loại. Vui lòng phân loại trước khi tạo lượt khám." |
B2.4) Phản hồi sau thao tác
| Hành động | Phản hồi |
|---|---|
| Lưu thành công | "Đã tạo lượt khám cho khách {customer_name}" + mở Bàn việc bác sĩ nếu người dùng là BS |
| Bỏ qua tạo KH inline | Nút "Lưu lượt khám" ở trạng thái khoá + tooltip "Vui lòng chọn hoặc tạo khách hàng trước" |
| Không có quyền | CTA ẩn; route/action trả "Bạn không có quyền tạo lượt khám" |
SCR-06: Form BA Da liễu
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Bác sĩ Da liễu cùng CN với KH |
| Vào màn để quyết định gì? | Khám và chốt chẩn đoán ICD-10 + y lệnh + phiếu biểu mẫu kèm theo |
| Dữ liệu chính | clinical_record (form_type='DL'), clinical_form_instance (form_template DL), ICD-10 |
| CTA chính / phụ | Primary: "Hoàn thành" (chỉ mở khi đầy đủ + allergy đạt); Secondary: "In bộ hồ sơ" (sau hoàn thành), "Lưu nháp" (auto 30s) |
| Điều không được hiểu nhầm | "Hoàn thành" chỉ chuyển trạng thái completed — chưa in, chưa scan |
B2.2) Wireframe — Demo độc lập (Xây mới)
text
/e/service-order/clinical-records/{id}/ba-dl [Bệnh án Da liễu]
Header: KH Lê Thị Hương · Mã BA: DVA-DL-CL-2026-00147
BS Trần Mỹ Hương · CN Cao Lãnh · Lượt khám 02/05/2026 14:30
Trạng thái: [Bản nháp] Đã lưu nháp lúc 14:32
┌─ 1. Hành chính (KEEP — đã có thông tin từ appointment) ──────────────┐
│ Tuổi: 28 · Giới tính: Nữ · Nghề nghiệp: [Văn phòng] │
│ Địa chỉ: [Số 12, Đường Lê Lợi, P.1, TP. Cao Lãnh] │
└─────────────────────────────────────────────────────────────────────┘
┌─ 2. Tiền sử ─────────────────────────────────────────────────────── [▼]┐
│ Tiền sử dị ứng: ◉ Không đổi (reuse phiếu trước) ○ Điền mới │
│ Tiền sử bệnh nội khoa: [Đái tháo đường týp 2 từ 2022] │
│ Tiền sử dị ứng thuốc: [Penicillin (nổi mẩn 2020)] │
│ Thuốc đang dùng: [Metformin 500mg, 2 viên/ngày] │
└─────────────────────────────────────────────────────────────────────┘
┌─ 3. Khám hiện tại ──────────────────────────────────────────────── [▼]┐
│ Lý do đến: [Mụn trứng cá tái phát 3 tháng] │
│ Tổn thương cơ năng: [Ngứa, đỏ vùng má 2 bên] │
│ Khám da liễu chi tiết: │
│ - Vị trí: [Má, trán, cằm] │
│ - Loại tổn thương: ☑ Mụn viêm ☑ Mụn đầu đen ☐ Sẹo │
│ - Mức độ: ◉ Trung bình ○ Nhẹ ○ Nặng │
│ Khám toàn thân: [Sinh hiệu ổn, không hạch] │
└─────────────────────────────────────────────────────────────────────┘
┌─ 4. Chẩn đoán ──────────────────────────────────────────────────── [▼]┐
│ Chẩn đoán chính (ICD-10) ★ Bắt buộc: │
│ [L70.0 — Mụn trứng cá thông thường ▼] │
│ Mã giấy lưu trữ (nếu khác): [—] │
│ Chẩn đoán phụ (0-5 mã): │
│ [L73.2 — Viêm da quanh miệng] [×] │
│ [+ Thêm chẩn đoán phụ] │
│ Mô tả chi tiết: [Mụn trứng cá thông thường mức độ trung bình...] │
└─────────────────────────────────────────────────────────────────────┘
┌─ 5. Y lệnh ──────────────────────────────────────────────────────── [▼]┐
│ Liệu trình điều trị: [Áp lạnh nitơ + thuốc bôi adapalene 0.1%] │
│ Lời dặn: [Tránh nắng, không nặn mụn, tái khám sau 4 tuần] │
│ [+ Tạo đơn thuốc] [+ Phiếu cam đoan] [+ Phiếu cam kết] │
└─────────────────────────────────────────────────────────────────────┘
┌─ 6. Theo dõi ─────────────────────────────────────────────────── [▼]┐
│ Lịch tái khám: [30/05/2026] │
│ Ghi chú BS: [Theo dõi đáp ứng sau 4 tuần áp lạnh] │
└─────────────────────────────────────────────────────────────────────┘
⚠ An toàn dị ứng: KT "Áp lạnh nitơ" có rủi ro thấp — cho phép hoàn thành.
[Hủy] [Lưu nháp] [Hoàn thành]B2.4) Quy ước field — ref B0.4: clinical_record.diagnosis_codes, clinical_form_instance.form_data
B2.7) Quy ước tương tác
| Tình huống | Hành vi |
|---|---|
| Autosave 30s | FE debounce 30s sau khi BS dừng gõ → mutation; show "Đã lưu nháp lúc HH:mm" |
| Mở/đóng phần | Bấm tiêu đề phần → mở/đóng phần đó; mặc định mở các phần đã có dữ liệu |
| ICD-10 dropdown | Searchable, fetch dần (paginated 50/page); typeahead 200ms debounce |
| Conflict (BS khác cùng record) | Hộp thoại "Có thay đổi từ thiết bị khác. Giữ thay đổi của bạn / Lấy bản mới nhất" |
| Mất mạng | Thông báo nhanh "Mất kết nối. Đã lưu local. Đang thử lại..." + auto-retry |
B2.10) Phản hồi sau thao tác
| Hành động | Phản hồi |
|---|---|
| Lưu nháp (auto) | Thông báo nhanh nhỏ "Đã lưu nháp lúc HH:mm" |
| Hoàn thành (đạt allergy) | Thông báo nhanh "Đã hoàn thành bệnh án {DVA-DL-CL-2026-00147}" + chuyển sang chế độ readonly |
| Hoàn thành (allergy unknown/high block) | Banner đỏ "Bắt buộc điền Phiếu tiền sử dị ứng trước thủ thuật xâm lấn" + CTA "Mở phiếu dị ứng" |
| Thiếu ICD chính-10 | Lỗi tại field + focus field "Chẩn đoán chính" + "Vui lòng chọn ít nhất 1 mã ICD-10 chính" |
B2.11) Mapping UI theo LIFECYCLE-002
| Trạng thái | CTA hiển thị | CTA ẩn/khóa | Field sửa được | Badge |
|---|---|---|---|---|
Bản nháp | Lưu nháp, Hoàn thành | In, Tải bản scan đã ký | Tất cả | "Bản nháp" (vàng) |
Đã hoàn thành | In bộ hồ sơ, Sửa (nếu có quyền edit_medical_form) | Hoàn thành | Readonly (chỉ sửa qua "Sửa" → tạo bản v2) | "Đã hoàn thành" (xanh) |
Đã in | Tải bản scan đã ký, In lại | Sửa (chỉ qua tạo bản v2) | Readonly | "Đã in" (xanh đậm) |
Đã ký + scan đủ | Xem | In bản v2 (chỉ qua luồng đặc biệt) | Readonly | "Đã ký + scan đủ" (xanh đậm + ✓) |
Bản thay thế | Xem | — | Readonly | "Bản thay thế" (xám) |
Đã lưu trữ | Xem (chỉ Admin) | — | Readonly | "Đã lưu trữ" (xám đậm) |
SCR-07: Form BA Thẩm mỹ (4 phân hệ)
B2.2) Wireframe
text
/e/service-order/clinical-records/{id}/ba-tm [Bệnh án Thẩm mỹ]
Header: KH Nguyễn Thị Lan · Mã BA: DVA-TM-TB2-2026-00089
BS Phạm Hoàng Long · CN Tân Bình II · 02/05/2026 09:00
Dịch vụ: Nâng mũi cấu trúc (15.000.000đ) → Auto-hiện section Mũi
┌─ 1. Hành chính + Tiền sử (KEEP) ─────────────────────────────── [▼]┐
│ ... (như BA DL) │
└────────────────────────────────────────────────────────────────────┘
┌─ 2. Phân hệ MŨI (auto-hiện) ─────────────────────────────────── [▼]┐
│ Đo đạc: │
│ - Chiều cao sống mũi: [3.2 mm] │
│ - Độ rộng cánh mũi: [38 mm] │
│ - Góc mũi-môi: [95°] │
│ - Tỉ lệ chiều dài/rộng: [1:0.7] │
│ Tình trạng hiện tại: [Sống mũi thấp, đầu mũi bè] │
│ Phân tích thẩm mỹ: │
│ ☑ Mũi tẹt ☑ Đầu mũi bè ☐ Lệch sống ☐ Cánh mũi rộng │
└────────────────────────────────────────────────────────────────────┘
┌─ 3. Phân hệ MẮT (chưa bật) [+ Bật phân hệ Mắt] │
│ ⚠ Phân hệ này không được chọn từ dịch vụ POS. Bật chỉ khi cần. │
└────────────────────────────────────────────────────────────────────┘
┌─ 4. Phân hệ MÔI (chưa bật) [+ Bật phân hệ Môi] │
└────────────────────────────────────────────────────────────────────┘
┌─ 5. Phân hệ KHÁC (chưa bật) [+ Bật phân hệ Khác] │
└────────────────────────────────────────────────────────────────────┘
┌─ 6. Chẩn đoán + Y lệnh + Theo dõi (như BA DL) ─────────────────────┐
│ ICD-10 chính ★: [Q67.4 — Bất thường hình thái mũi bẩm sinh ▼] │
│ ... │
└────────────────────────────────────────────────────────────────────┘
⚠ An toàn dị ứng: KT "Phẫu thuật nâng mũi" rủi ro CAO — bắt buộc Phiếu dị ứng.
[Hủy] [Lưu nháp] [Hoàn thành] (bị khóa cho tới khi có Phiếu dị ứng)B2.7) auto-hiện section theo dịch vụ; bật thêm có warning + log ghi chú.
SCR-08: Năm biểu mẫu dùng chung / đi kèm
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Bác sĩ nhập nội dung y khoa; y tá hỗ trợ phần hành chính/scan; KH ký trên bản giấy sau khi in |
| Vào màn để quyết định gì? | Điền các Phiếu biểu mẫu đi kèm trước khi in bộ hồ sơ |
| Dữ liệu chính | form_template, clinical_form_instance, prescription, prescription_item, allergy_check_policy |
| CTA chính / phụ | Primary: "Lưu phiếu"; Secondary: "Thêm đơn thuốc", "Mở phiếu dị ứng", "Xem trước bản in" |
| Điều không được hiểu nhầm | Phiếu theo dõi điều trị chỉ bắt buộc cho case TM có điều trị nhiều lần; không bắt buộc cho mọi BA |
B2.2) Bố cục tab biểu mẫu
text
[Biểu mẫu đi kèm — DVA-TM-TB2-2026-00089] [×]
Tabs:
[Cam đoan] [Cam kết] [Đơn thuốc] [Dị ứng] [Theo dõi điều trị]
┌─ Cam đoan thực hiện dịch vụ ───────────────────────────────────────┐
│ Khách hàng: Nguyễn Thị Lan · Dịch vụ: Nâng mũi cấu trúc │
│ │
│ ☑ Tôi đã được bác sĩ tư vấn về lợi ích, nguy cơ và chăm sóc sau thủ thuật.
│ ☑ Tôi đồng ý thực hiện dịch vụ theo tư vấn.
│ │
│ Câu xác nhận khách tự gõ trên hệ thống (≥20 ký tự, phải chứa "đồng │
│ ý" hoặc "thực hiện"; FE chặn dán/copy-paste để buộc gõ tay): │
│ [Tôi đã hiểu nội dung tư vấn và đồng ý thực hiện dịch vụ này. ] *
│ │
│ Người làm chứng: [Y tá Hà ▼] │
└─────────────────────────────────────────────────────────────────────┘
[Lưu phiếu] [Xem trước bản in] [Đóng]Rule câu xác nhận tự gõ (DEC-021):
| Kiểm tra | Quy ước |
|---|---|
| Độ dài | ≥ 20 ký tự (sau trim) |
| Từ khóa | Phải chứa "đồng ý" hoặc "thực hiện" (case-insensitive) |
| Chống dán | FE bắt sự kiện paste ở textarea này → ngăn dán + thông báo nhanh "Vui lòng để khách tự gõ trên màn hình" |
| Tốc độ gõ | FE log nhịp phím; nếu ≥10 ký tự liên tiếp xuất hiện trong <50ms → cảnh báo nhân viên + yêu cầu khách gõ lại |
| Server | Validate lại độ dài + từ khóa; lưu kèm typed_at, typed_duration_ms để audit |
B2.3) Danh sách phiếu và rule bắt buộc
| Phiếu biểu mẫu | Khi nào hiện | Khi nào bắt buộc | Field chính | In trong bộ hồ sơ |
|---|---|---|---|---|
| Cam đoan | Dịch vụ thủ thuật/xâm lấn | Khi technical_category.requires_consent=true | Checkbox đồng ý + câu xác nhận tự gõ | Có |
| Cam kết | Dịch vụ có cam kết chăm sóc/hậu phẫu | Theo cấu hình dịch vụ/kỹ thuật | Nội dung cam kết, người tư vấn, ghi chú | Có |
| Đơn thuốc | BS kê thuốc | Khi có ít nhất 1 thuốc | Tên thuốc, hàm lượng, số lượng, cách dùng, lời dặn | Có |
| Phiếu tiền sử dị ứng | Lần đầu hoặc KT rủi ro medium/high/unknown | Bắt buộc với KT xâm lấn/rủi ro cao | Dị ứng thuốc/thức ăn/vật liệu, mức độ, xử trí | Có |
| Phiếu theo dõi điều trị | Case TM nhiều lần hoặc hậu phẫu | Bắt buộc khi form_type='TM' và kỹ thuật yêu cầu theo dõi | Ngày theo dõi, diễn biến, xử trí, hẹn tái khám | Có nếu phát sinh |
B2.4) Đơn thuốc
text
[Đơn thuốc]
Chẩn đoán: L70.0 — Mụn trứng cá thông thường
┌────┬────────────────────┬──────────┬──────────┬───────────────┬─────────┐
│ # │ Thuốc │ Hàm lượng│ Số lượng │ Cách dùng │ Xóa │
├────┼────────────────────┼──────────┼──────────┼───────────────┼─────────┤
│ 1 │ Doxycycline │ 100mg │ 14 viên │ 1 viên/ngày sau ăn │ [×] │
│ 2 │ Adapalene gel │ 0.1% │ 1 tuýp │ Bôi tối, tránh mắt │ [×] │
└────┴────────────────────┴──────────┴──────────┴───────────────┴─────────┘
[+ Thêm thuốc] Lời dặn: [Tránh nắng, tái khám sau 4 tuần]B2.5) Quy ước tương tác
| Tình huống | Hành vi |
|---|---|
| Mở phiếu từ BA DL/TM | Popup giữ context record; lưu xong quay lại đúng section |
| Thiếu phiếu bắt buộc | Form BA không cho "Hoàn thành"; banner có CTA mở phiếu thiếu |
| Phiếu đã in | Chuyển chỉ đọc; sửa sau in tạo bản v2 theo DEC-023 |
| KH từ chối ký bản giấy | Chuyển sang SCR-10 tab "Biên bản từ chối"; không sửa nội dung phiếu đã hoàn thành |
| KH từ chối thủ thuật (DEC-024) | Bấm "Khách từ chối thủ thuật" trong Cam đoan → mở hộp thoại: (1) chọn lý do từ chối; (2) ghi chú; (3) y tá làm chứng (dropdown nhân viên cùng CN); (4) hệ thống tự huỷ order_item của thủ thuật trong đơn (cần quyền order.update) và đánh dấu lượt khám là "Khám tư vấn — không thực hiện thủ thuật"; ghi sổ khám với cột "Kết quả: Khách từ chối thủ thuật"; KHÔNG tạo Bệnh án thủ thuật, vẫn giữ Bệnh án lượt khám DL nếu đã có |
| Y tá không có quyền tầng 3 | Chỉ sửa phần hành chính/shared được cấp; không thấy chẩn đoán/ghi chú BS |
B2.6) Copy lỗi
| Lỗi | Copy |
|---|---|
| Thiếu câu xác nhận | "Vui lòng nhập câu xác nhận trước khi lưu phiếu cam đoan." |
| Đơn thuốc thiếu cách dùng | "Vui lòng nhập cách dùng cho thuốc {medicine_name}." |
| Phiếu dị ứng chưa đủ | "Vui lòng hoàn thành Phiếu tiền sử dị ứng trước khi hoàn thành bệnh án." |
| Không có quyền sửa | "Bạn không có quyền sửa phiếu này. Vui lòng liên hệ bác sĩ phụ trách." |
SCR-09: Xem trước PDF + In bộ hồ sơ
text
[Xem trước bộ hồ sơ — DVA-DL-CL-2026-00147] [×]
┌──────────────────────────────────────────────────────────────────┐
│ ┌─ Trang 1/8: Bệnh án Da liễu ─────────────────────────────────┐ │
│ │ PHÒNG KHÁM DA LIỄU DIVA CAO LÃNH │ │
│ │ Giấy phép số: 123/SYT-DT STT: DVA-CL-00147/2026 │ │
│ │ Mã BA: DVA-DL-CL-2026-00147 │ │
│ │ │ │
│ │ KH: Lê Thị Hương · 28 tuổi · Nữ │ │
│ │ ... │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Bộ hồ sơ gồm: BA DL (3 trang) + Cam đoan (1 trang) │
│ + Đơn thuốc (1 trang) + Phiếu dị ứng (1 trang) │
│ + Phiếu theo dõi điều trị (2 trang) = 8 trang │
└──────────────────────────────────────────────────────────────────┘
[← Trang trước] Trang 1/8 [Trang sau →]
[Đóng] [Tải PDF] [In bộ hồ sơ]B2.10)
| Hành động | Phản hồi |
|---|---|
| Bấm "In bộ hồ sơ" | Hiện hộp thoại in của trình duyệt → render PDF; trạng thái Đã in; thông báo nhanh "Đã in bộ hồ sơ. Vui lòng ký tay và tải bản scan đã ký." |
| Tải PDF | Download file BA-DVA-DL-CL-2026-00147.pdf |
SCR-10: Tải bản scan đã ký
text
[Tải bản scan đã ký — DVA-DL-CL-2026-00147] [×]
Trạng thái BA: [Đã in] Sẽ chuyển sang [Đã ký + scan đủ] khi đủ checklist.
┌─ Checklist scan bắt buộc (theo case BA DL có thủ thuật + đơn thuốc) ──┐
│ ☐ BA chính (3 trang) │
│ ☐ Cam đoan (1 trang) │
│ ☐ Cam kết (1 trang) │
│ ☐ Đơn thuốc (1 trang) │
│ ☑ Phiếu tiền sử dị ứng — không bắt buộc cho ca này │
│ ☑ Phiếu theo dõi điều trị — không bắt buộc cho ca này │
│ │
│ Hoặc: ☐ Biên bản từ chối ký (KH từ chối) + Y tá làm chứng │
└───────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ ☁ Kéo-thả file scan vào đây │
│ hoặc [Chọn file] (PDF, JPG, PNG — tối đa 20MB/file) │
└──────────────────────────────────────────────────────────────────────┘
Đã tải:
┌──────────────────────────────────────────────────┬──────────────────┐
│ ba-le-thi-huong-2026-05-02.pdf (1.2MB) │ Map: [BA chính ▼] │
│ ✓ Đã tải │ ✓ OK │
├──────────────────────────────────────────────────┼──────────────────┤
│ cam-doan.pdf (350KB) │ Map: [Cam đoan ▼] │
│ ✓ Đã tải │ ✓ OK │
└──────────────────────────────────────────────────┴──────────────────┘
[Hủy] [Lưu] (chuyển trạng thái)B2.10)
| Trường hợp | Phản hồi |
|---|---|
| Đủ checklist | Thông báo nhanh "Đã ký + scan đủ — bệnh án hoàn tất pháp lý" + trạng thái chuyển |
| Thiếu checklist | Banner "Còn thiếu: Cam kết, Đơn thuốc" + trạng thái vẫn Đã in |
| KH từ chối ký | Tab "Biên bản từ chối" + checkbox "Y tá làm chứng" + dropdown chọn y tá → trạng thái Đã ký + scan đủ với refusal_witnessed=true |
SCR-11: Sổ khám bệnh
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | QL CN, Admin/Ops, bác sĩ được quyền xuất sổ |
| Vào màn để quyết định gì? | Theo dõi lượt khám ngoại trú theo ngày/CN, phục vụ vận hành và thanh tra |
| Dữ liệu chính | clinical_record, clinical_profile, appointment, customer, doctor, diagnosis_codes |
| CTA chính / phụ | Primary: "Xuất Excel"; Secondary: "Xem bệnh án", "Tải bản scan đã ký", "Mở bộ lọc" |
| Điều không được hiểu nhầm | Người không có view_medical_detail vẫn xem được sổ nhưng cột chẩn đoán hiển thị "—" |
B2.2) Bố cục
text
/e/service-order/clinical-visit-log [Sổ khám bệnh]
Header: Sổ khám bệnh · CN: Cao Lãnh · Ngày 02/05/2026
[Từ ngày 01/05/2026] [Đến ngày 02/05/2026] [CN: Cao Lãnh ▼]
[Loại BA: Tất cả ▼] [Trạng thái BA: Tất cả ▼] [Bác sĩ: Tất cả ▼]
[Tìm mã BA / tên KH / SĐT...] [Xuất Excel]
Tổng: 48 lượt khám · Đã ký+scan đủ: 36 · Cần scan: 8 · Bản nháp: 4
┌────┬──────────┬─────────────┬──────────────┬──────────┬──────────┬──────────┬────────────┐
│ # │ Ngày khám│ STT sổ khám │ Khách hàng │ Tuổi/Giới│ Bác sĩ │ ICD chính│ Trạng thái │
├────┼──────────┼─────────────┼──────────────┼──────────┼──────────┼──────────┼────────────┤
│ 1 │02/05/26 │DVA-CL-00147 │Lê Thị Hương │28/Nữ │BS Hương │L70.0 │Đã ký+scan │
│ 2 │02/05/26 │DVA-CL-00148 │Phạm Hà │34/Nữ │BS Hương │— │Cần scan │
│ 3 │02/05/26 │DVA-CL-00149 │Khách walk-in│— │BS Phát │— │Bản nháp │
└────┴──────────┴─────────────┴──────────────┴──────────┴──────────┴──────────┴────────────┘
Row action: [Xem] [In lại] [Tải bản scan đã ký]B2.3) Cột dữ liệu
| Cột | Nguồn | Format | Quyền |
|---|---|---|---|
| STT | visit_log_number | DVA-[CN]-[NNNNN]/[YYYY] | view_summary |
| Ngày khám | appointment.started_at hoặc clinical_record.created_at | DD/MM/YYYY HH:mm | view_summary |
| Khách hàng | customer.full_name, phone masked nếu cần | Text | view_summary |
| Bác sĩ | doctor.full_name | Text | view_summary |
| Chẩn đoán chính | diagnosis_codes.primary | ICD-10 + tên bệnh | view_medical_detail; thiếu quyền → "—" |
| Trạng thái BA | clinical_record.status | Badge canonical | view_summary |
| Scan | scan_checklist | "Đủ", "Thiếu {N}" | view_summary |
B2.4) Bộ lọc và export
| Bộ lọc | Mặc định | Ghi chú |
|---|---|---|
| Khoảng ngày | Hôm nay | Không quá 90 ngày/lần xuất |
| Chi nhánh | CN hiện tại nếu branch scope | Admin/Ops được chọn nhiều CN |
| Trạng thái BA | Tất cả | draft/completed/printed/signed/... |
| Loại BA | Tất cả | DL/TM |
| Bác sĩ | Tất cả | Lọc theo nhân sự thuộc CN |
| Từ khóa | Rỗng | Tìm mã BA, STT sổ, tên KH, SĐT |
B2.5) Trạng thái và copy
| Tình huống | Copy |
|---|---|
| Không có dữ liệu | "Chưa có lượt khám trong khoảng thời gian này." |
| Không có quyền export | Ẩn nút "Xuất Excel"; route/API vẫn kiểm clinical_record.export_visit_log |
| Export thành công | "Đã xuất Sổ khám bệnh {from}-{to}. Bấm để tải về." |
| Export có masking | "Đã xuất {X} dòng. {Y} cột y tế nhạy cảm bị ẩn theo phân quyền." |
SCR-12: Sổ thủ thuật
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | QL CN, Admin/Ops, bác sĩ/phụ trách thủ thuật |
| Vào màn để quyết định gì? | Theo dõi ca thủ thuật/thẩm mỹ, kỹ thuật thực hiện, biến chứng và trạng thái scan |
| Dữ liệu chính | clinical_record, technical_category, procedure_log_number, reference_file, clinical_form_instance |
| CTA chính / phụ | Primary: "Xuất Excel"; Secondary: "Xem bệnh án", "Xem phiếu theo dõi điều trị" |
| Điều không được hiểu nhầm | Sổ thủ thuật chỉ lấy record có kỹ thuật thủ thuật; không lấy tư vấn hoặc dịch vụ spa không cần BA |
B2.2) Bố cục
text
/e/service-order/clinical-procedure-log [Sổ thủ thuật]
[Từ ngày 01/05/2026] [Đến ngày 02/05/2026] [CN: Tân Bình II ▼]
[Kỹ thuật: Tất cả ▼] [Trạng thái scan: Tất cả ▼] [Bác sĩ: Tất cả ▼]
[Tìm STT thủ thuật / tên KH...] [Xuất Excel]
Tổng: 18 ca thủ thuật · Có biến chứng: 1 · Cần scan: 3
┌────┬──────────┬──────────────┬──────────────┬────────────┬──────────┬────────────┬──────────┐
│ # │ Ngày │ STT thủ thuật│ Khách hàng │ Kỹ thuật │ Bác sĩ │ Theo dõi │ Scan │
├────┼──────────┼──────────────┼──────────────┼────────────┼──────────┼────────────┼──────────┤
│ 1 │02/05/26 │DVA-TB2-TT... │Nguyễn Lan │Nâng mũi │BS Long │Có │Đủ │
│ 2 │02/05/26 │DVA-TB2-TT... │Mai Anh │Tiêm filler │BS Long │Không │Thiếu 1 │
│ 3 │01/05/26 │DVA-TB2-TT... │Trần Hoa │Cắt mí │BS Phát │Có biến chứng│Đủ │
└────┴──────────┴──────────────┴──────────────┴────────────┴──────────┴────────────┴──────────┘
Row action: [Xem BA] [Xem theo dõi] [Tải bản scan đã ký]B2.3) Cột dữ liệu
| Cột | Nguồn | Format | Quyền |
|---|---|---|---|
| STT thủ thuật | procedure_log_number | DVA-[CN]-TT-[NNNNN]/[YYYY] | view_summary |
| Kỹ thuật | technical_category.name | Text | view_summary |
| Vật tư chính | form TM / phiếu theo dõi | Text hoặc "—" | view_medical_detail; thiếu quyền → "—" |
| Biến chứng | phiếu theo dõi điều trị | "Không", "Có", "Chờ cập nhật" | view_medical_detail; thiếu quyền → chỉ thấy "Có/Không" nếu được policy cho |
| Theo dõi điều trị | treatment_progress_entry | Có/Không | view_summary |
| Scan | scan_checklist | Đủ/Thiếu | view_summary |
B2.4) Quy ước export
| Trường hợp | Hành vi |
|---|---|
User có view_medical_detail | Export đủ ICD, kỹ thuật, diễn biến, vật tư nếu policy cho |
User chỉ có view_summary | Export vẫn chạy nhưng cột y tế nhạy cảm là "—" |
| Có >5.000 dòng | UI yêu cầu thu hẹp khoảng ngày hoặc tạo export job nền |
| Không có dữ liệu | Copy: "Chưa có ca thủ thuật trong khoảng thời gian này." |
SCR-13: Trang xem an toàn (Sale)
text
/crm/customer/{id}/sales-safe-clinical [Trang xem an toàn — Tư vấn]
Header: KH Lê Thị Hương · Đã đến CN Cao Lãnh 12 lần
⚠ Cảnh báo an toàn (chỉ tóm tắt):
┌──────────────────────────────────────────────────────┐
│ ⚠ MỨC CAO: Có 1 cảnh báo dị ứng │
│ — Vui lòng chuyển bác sĩ tư vấn dịch vụ liên quan │
│ thuốc tiêm để xác nhận an toàn. │
├──────────────────────────────────────────────────────┤
│ ℹ Trung bình: Có bệnh nền cần lưu ý │
│ — Tư vấn cẩn thận với liệu trình thẩm mỹ xâm lấn. │
└──────────────────────────────────────────────────────┘
Lịch sử dịch vụ (12 lượt):
┌───────────┬────────────────────────┬──────────────┬──────────┐
│ Ngày │ Dịch vụ │ Chi nhánh │ Số tiền │
├───────────┼────────────────────────┼──────────────┼──────────┤
│ 02/04/26 │ Liệu trình trị mụn │ Cao Lãnh │ 3.5tr │
│ 15/03/26 │ Tẩy trang sâu │ Cao Lãnh │ 0.8tr │
│ ... │ │ │ │
└───────────┴────────────────────────┴──────────────┴──────────┘
Số bệnh án: 5 · Bệnh án gần nhất: 02/04/2026
[Chuyển bác sĩ tư vấn] [Ghi chú kỳ vọng KH]B2.4) Field hiển thị (ref B3.0.2 ma trận tầng dữ liệu — Sale chỉ thấy tầng 1+2)
Quy định cứng: Sale KHÔNG bao giờ thấy: chẩn đoán, ICD-10, ghi chú BS, đơn thuốc, ảnh y tế tầng 3, bản scan đã ký. Bấm "Chuyển bác sĩ tư vấn" → form handoff với kiểm tra regex chống ghi chẩn đoán/mã ICD vào safe note.
B2.5) Hành vi click trên Lịch sử dịch vụ
| Click vào | Hành vi cho Sale |
|---|---|
| Tên dịch vụ trong lịch sử | Mở popup "Tóm tắt dịch vụ" (tên dịch vụ, CN, ngày, số tiền, ghi chú quầy đã được lọc theo Trang xem an toàn) — KHÔNG link sang BA / form / scan |
| Cảnh báo an toàn (alert level/code) | Tooltip mô tả mức cảnh báo (ví dụ "Mức cao") + gợi ý "Vui lòng chuyển bác sĩ để xem chi tiết" — KHÔNG show diagnosis/ICD |
| "Chuyển bác sĩ tư vấn" | Mở SCR-handoff với expectations + safe notes; backend regex chặn nội dung chứa thuật ngữ y khoa, mã ICD, tên thuốc kê đơn |
| "Ghi chú kỳ vọng KH" | Mở textarea ghi vào customer.crm_note (hiện hữu) — KHÔNG ghi vào clinical_* |
SCR-14: Bàn việc bác sĩ
text
/e/service-order/doctor-workbench [Bàn việc bác sĩ]
Header: BS Trần Mỹ Hương · CN Cao Lãnh · Hôm nay 02/05/2026
┌─ Tổng quan ──────────────────────────────────────────────────────┐
│ 6 nhóm việc · Tổng 13 việc │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────┬──────────────────────┬──────────────────────┐
│ 🆕 Cần tạo BA (3) │ 📝 BA nháp (2) │ 🖨 Cần in (1) │
├──────────────────────┼──────────────────────┼──────────────────────┤
│ • KH Lê Hương │ • KH Vũ Trang │ • KH Phạm Hà │
│ Liệu trình mụn │ BA TM nháp 1h │ BA DL hoàn thành │
│ [Tạo BA →] │ [Mở nháp →] │ [In →] │
│ │ │ │
│ • KH Đỗ Linh │ • KH Bùi Mai │ │
│ Filler │ BA DL nháp 30p │ │
│ [Tạo BA →] │ [Mở nháp →] │ │
│ │ │ │
│ • KH Nguyễn Lan │ │ │
│ Nâng mũi │ │ │
│ [Tạo BA →] │ │ │
└──────────────────────┴──────────────────────┴──────────────────────┘
┌──────────────────────────┬─────────────────────────┬──────────────────────────┐
│ 📎 Cần scan (4) │ 🤝 Sale chuyển (1) │ 📋 Tự khai chờ (2) │
├──────────────────────────┼─────────────────────────┼──────────────────────────┤
│ • DVA-DL-CL-2026-00145 │ • Sale Hồng chuyển │ • KH Trần Hà │
│ 2 ngày chưa scan │ KH Hoa │ Phiếu tự khai chờ nhận │
│ [Tải bản scan →] │ [Xem ghi chú →] │ [Rà soát →] │
│ │ │ │
│ • DVA-TM-CL-2026-00089 │ │ • KH Lý Mai │
│ 1 ngày chưa scan │ │ [Rà soát →] │
│ [Tải bản scan →] │ │ │
│ │ │ │
│ • ... (2 BA nữa) │ │ │
└──────────────────────────┴─────────────────────────┴──────────────────────────┘
[Tải lại]B2.7)
| Tình huống | Hành vi |
|---|---|
| Bấm nhóm việc | Mở danh sách đã lọc; bấm một việc → luồng tương ứng (tạo BA / mở nháp / in / scan / nhận chuyển từ Sale / rà soát phiếu khách tự khai) |
| Việc hoàn thành | Tự bỏ khỏi nhóm việc; thông báo nhanh "Đã hoàn thành việc" |
| Kéo để tải lại | Tải lại tất cả 6 nhóm việc |
| Cập nhật tức thời | (Phase 2 — WebSocket); Day-1 polling 60 giây |
SCR-15: Phiếu khách tự khai (cổng tablet quầy theo token)
text
/p/customer-clinical-intake/{token} [Phiếu khách tự khai — Tablet]
🌸 Kính chào quý khách Lê Thị Hương ⏱ Còn 14:23
Vui lòng điền thông tin sau trước khi gặp bác sĩ:
1. Tiền sử dị ứng (chọn nhiều)
☐ Penicillin ☐ Aspirin ☐ Hải sản
☐ Đậu phộng ☐ Mủ cao su ☐ Khác: [_______]
☐ Tôi không có dị ứng
2. Bệnh nền (chọn nhiều)
☐ Đái tháo đường ☐ Cao huyết áp ☐ Tim mạch
☐ Hen suyễn ☐ Khác: [_______]
☐ Tôi không có bệnh nền
3. Thuốc đang dùng (text)
[Metformin 500mg, ngày 2 viên ]
4. Đã từng phẫu thuật/thủ thuật?
◉ Có ○ Không
Nếu có, ghi rõ: [Cắt amidan 2018 ]
5. Đang mang thai?
○ Có ◉ Không ○ Không chắc
[Lưu nháp] [Hoàn thành — gửi cho bác sĩ →]B2.7)
| Tình huống | Hành vi |
|---|---|
| Hết hạn 15 phút | Banner "Phiên đã hết hạn. Vui lòng nhờ lễ tân mở lại." + bị khóa gửi |
| Gửi | Server kiểm tra appointment/customer/branch khớp token → lưu customer_clinical_intake.form_data |
| BS rà soát | BS thấy nhóm việc "Phiếu tự khai chờ" trong Bàn việc bác sĩ → mở màn rà soát → bấm "Nhận vào hồ sơ" → ghi vào clinical_form_instance với source_type='customer_intake' |
SCR-16: Trang điều phối phòng khám
text
/e/service-order/clinic-ops-dashboard [Điều phối phòng khám — Toàn chuỗi]
Vai trò: Ops · Lọc: Tất cả CN ▼ · [Ngày: Hôm nay ▼]
┌─ Tổng quan toàn chuỗi (12 CN đang hoạt động) ──────────────────────┐
│ Đang hoạt động: 10 CN · Tạm dừng: 1 · Đang cấu hình: 1 │
│ ⚠ Cần Ops xử lý: 5 cảnh báo │
└────────────────────────────────────────────────────────────────────┘
┌─ CN Cao Lãnh ─────────────────────┬─ CN Tân Bình II ────────────────┐
│ [Đang hoạt động] │ [Đang hoạt động] │
│ │ │
│ Hôm nay: 15 lượt khám │ Hôm nay: 22 lượt khám │
│ • 12 hoàn thành ✓ │ • 18 hoàn thành ✓ │
│ • 2 nháp ⚠ │ • 3 nháp │
│ • 1 cần scan ⚠ │ • 1 cần scan │
│ │ │
│ Lệch cấu hình: │ Lệch cấu hình: │
│ ⚠ 3 dịch vụ chưa phân loại │ ✓ Không có lệch cấu hình │
│ [Đến danh mục dịch vụ →] │ │
│ │ │
│ Mở quyền khẩn cấp hôm nay: 0 │ Mở quyền khẩn cấp: 1 (BS Long) │
│ │ [Xem audit log →] │
│ │ │
│ Cutoff: 20:00 · Trạng thái: chờ │ Cutoff: 19:30 · Đã chốt 19:35 │
│ [Chốt ngày] │ ✓ Đã chốt │
└────────────────────────────────────┴──────────────────────────────────┘
... (10 CN khác)
[Xuất báo cáo Excel]SCR-17: Hộp thoại Chốt ngày phòng khám
text
[Chốt ngày phòng khám — CN Cao Lãnh — 02/05/2026] [×]
⚠ Còn việc chưa hoàn tất:
• 2 bệnh án còn ở "Bản nháp" (BS Hương: 2)
• 1 bệnh án "Đã in" chưa tải bản scan đã ký (DVA-DL-CL-2026-00145)
Bấm "Chốt ngày" sẽ:
✓ Ghi nhận trạng thái lúc {NOW}
✓ Gửi cảnh báo 1 BA ưu tiên cao chưa scan tới Ops + Medical Lead
✓ Khóa cron reminder cho ngày này
✓ Ghi audit `clinic_daily_close` với người chốt
Lý do (bắt buộc nếu còn BA ưu tiên cao chưa giải quyết):
[BS Hương sẽ hoàn thành 2 BA nháp sáng mai. Đã liên hệ KH Phạm Hà ]
[để hẹn quay scan ngày 03/05. ]
[Hủy] [Chốt ngày]SCR-18: Trang Compliance Audit Viewer
Tham chiếu:
permission-spec.mdP11.2. Day-1 build optional; nếu defer Phase 2 thì PD-PERM-004 phải resolved trước.
B2.1) Ngữ cảnh nghiệp vụ
| Câu hỏi | Cần chốt |
|---|---|
| Ai dùng? | Compliance officer, Admin/Ops, Medical Lead (xem audit của mình + branch scope) |
| Vào màn để quyết định gì? | Theo dõi truy cập tầng 3, emergency override, hard-deny attempts; phát hiện anomaly; export audit cho Sở Y tế |
| Dữ liệu chính | medical_record_access_log, emergency_override_session, permission_change_log, audit_export_log |
| CTA chính / phụ | Primary: "Xuất Excel"; Secondary: "Xem chi tiết event", "Force revoke override" (Phase 2), "Lọc nâng cao" |
| Điều không được hiểu nhầm | Compliance KHÔNG mở được form BA / scan; chỉ thấy metadata audit. Nội dung tầng 3 raw vẫn không expose qua trang này |
B2.2) Bố cục — Build mới
text
/s/compliance/clinical-audit [Compliance Audit Viewer]
Header: Compliance Audit · Filter Period: 01/05/2026 - 02/05/2026
[Bộ lọc:]
[Khoảng ngày: 01/05 - 02/05] [User: Tất cả ▼] [CN: Tất cả ▼]
[Action: Tất cả ▼] [Sensitivity: high+critical ▼] [Anomaly: Tất cả ▼]
[Tìm correlation_id / KH / mã BA...] [Xuất Excel]
Tổng: 1.247 events · Critical: 12 · High: 184 · Anomaly flagged: 3
┌────┬──────────────┬─────────────┬─────────┬──────────────────┬──────────┬────────────┬─────────┐
│ # │ Thời điểm │ Người dùng │ Vai trò │ Hành động │ CN │ Sensitivity│ Anomaly │
├────┼──────────────┼─────────────┼─────────┼──────────────────┼──────────┼────────────┼─────────┤
│ 1 │02/05 14:32:15│BS Hương │BS DL │view_medical_detail│Cao Lãnh │ high │ — │
│ 2 │02/05 14:30:08│BS Long │BS TM │emergency_override│Cao Lãnh→TBII│ critical│ ⚠ rate │
│ 3 │02/05 14:25:33│Sale Hồng │Sale │view_medical_detail│Cao Lãnh │ high │ ⛔ HARD │
│ 4 │02/05 14:20:11│Y tá Hà │Y tá │upload_scan │Cao Lãnh │ medium │ — │
└────┴──────────────┴─────────────┴─────────┴──────────────────┴──────────┴────────────┴─────────┘
Row action: [Xem chi tiết] [Mở record liên quan] [Filter user/action]B2.3) Cột dữ liệu
| Cột | Nguồn | Format | Quyền |
|---|---|---|---|
| Thời điểm | medical_record_access_log.created_at | DD/MM HH:mm:ss | clinical_record.export_visit_log |
| Người dùng | actor_user_id → join account | Tên + CN | ↑ |
| Vai trò | account.role (snapshot tại thời điểm event) | Text VI | ↑ |
| Hành động | action enum | Display VI + code backtick | ↑ |
| CN | branch_id | Branch code + tên | ↑ |
| Sensitivity | derived từ P1.2 | Badge color | ↑ |
| Anomaly | flag từ anomaly detection cron | Icon ⚠/⛔ | ↑ |
| Correlation ID | correlation_id | UUID truncated 8 ký tự | ↑ |
B2.4) Detail event modal
text
[Chi tiết event #1247] [×]
Correlation ID: f47ac10b
Thời điểm: 02/05/2026 14:32:15.234 +07:00
Người dùng: BS Trần Mỹ Hương (acc_doctor_huong)
Vai trò: BS DL · Portal: staff · Branch_mode: branch
CN của user: Cao Lãnh
Hành động: clinical_record.view_medical_detail · Sensitivity: high
Đối tượng:
• Loại: clinical_record
• ID: dva-dl-cl-2026-00147
• KH: Lê Thị Hương (cust_***456)
• CN của record: Cao Lãnh
Resolver output:
• Allowed: true
• View mode: full_tier3
• Branch scope: branch
• Field allowlist: 28 fields (ICD, diagnosis, form_data, prescription, ...)
• Audit required: true
IP / Device: 113.161.***.45 / desktop-chrome
Session ID (hash): 8a7b9c0d
Reason (nếu emergency): —
[Đóng] [Mở record liên quan]B2.5) Bộ lọc nâng cao
| Bộ lọc | Mặc định | Ghi chú |
|---|---|---|
| Khoảng ngày | 7 ngày gần nhất | Tối đa 90 ngày/lần xuất |
| User | Tất cả | Search by name / account_id |
| CN | Tất cả | Theo branch_assignment của Compliance officer |
| Action | Tất cả | Multi-select; default high+critical |
| Sensitivity | Tất cả | Quick filter: critical / high+critical / all |
| Anomaly | Tất cả | rate_limit / hard_deny / wrong_portal |
| Correlation ID | Rỗng | Trace cross-request |
B2.6) Trạng thái và copy
| Tình huống | Copy |
|---|---|
| Không có dữ liệu | "Không có event audit trong khoảng thời gian này." |
| Anomaly count > 0 | Banner đỏ trên cùng "Phát hiện {N} anomaly cần review" |
| Filter trả >5.000 dòng | "Khoảng quá rộng. Vui lòng thu hẹp filter hoặc dùng async export." |
| Export thành công | Thông báo nhanh "Đã xuất {X} dòng. Bấm để tải về." + audit audit_export_log |
| Force revoke (Phase 2) | Hộp thoại xác nhận "Force revoke session emergency của BS {name}? User sẽ mất quyền tầng 3 ngay." |
B2.7) Quy ước tương tác
| Tình huống | Hành vi |
|---|---|
| Click row | Mở detail modal |
| Click action filter | Apply ngay + reset paging |
| Click "Mở record liên quan" | Nếu Compliance có quyền → mở SCR-01 với context audit; nếu không → toast "Bạn không có quyền vào hồ sơ. Đây là log audit only." |
| Polling | 60s tự refetch (Compliance dashboard near-realtime) |
| Anomaly alert | Banner đỏ + push notification cho Compliance officer |
B2.8) Phân quyền
| Quyền | UI |
|---|---|
clinical_record.export_visit_log + flag compliance_role=true | Vào trang đầy đủ, export được |
| Admin/Ops không có flag compliance | Vào được nhưng không có cột "Anomaly" detail; không export raw audit |
| Medical Lead | Vào được, scope theo multi_branch assignment |
| Khác | Đường dẫn 401 |
B2.9) Hạn chế (Day-1)
- KHÔNG mở được form BA / scan từ trang này (chỉ metadata)
- Force revoke override = Phase 2 (cần workflow approval)
- Anomaly ML detect = Phase 3 (Day-1 chỉ rule-based đơn giản)
- Forward to authority = Phase 3
- Day-1 polling 60s; Phase 2 thêm WebSocket near-realtime
B3) Luồng người dùng
Luồng 1 — Admin bật module Phòng khám CN (5 bước + kiểm tra sẵn sàng)
Admin login Settings → Branch Detail CN Cao Lãnh
→ Tab "Phòng khám" → CTA "Bật module" → trạng thái=`setup_draft`
→ Bước 1: Loại PK = "Cả DL+TM" → Lưu, Tiếp
→ Bước 2: Tải giấy phép SYT 123/SYT-DT, expiry 2028-12-31 → Tiếp
→ Bước 3: Chọn 25 KT từ master (+ 2 KT tự thêm: Áp lạnh nitơ, Filler) → Tiếp
→ Bước 4: Phân loại 50 dịch vụ đang bán (45 cần BA + 5 không cần BA) → Tiếp
→ Bước 5: Cấp quyền: BS Hương + BS Long (BS DL/TM); Y tá Hà (admin_shared); QL CN Tâm → Lưu
→ Bước 6: Kiểm tra sẵn sàng R-01..R-10 → 10/10 Đạt
→ trạng thái=`ready_to_publish` → CTA "Phát hành" mở
→ Admin chọn effective_at = "02/05/2026 09:00" → trạng thái=`scheduled`
→ Cron 09:00 ngày 02/05 → trạng thái=`live`
→ UI clinical xuất hiện cho team CN Cao LãnhLuồng 2 — BS điền BA từ lịch hẹn (đường chuẩn)
KH Lê Hương đến quầy có lịch hẹn 14:30 → Lễ tân check-in
→ Bàn việc bác sĩ (BS Hương): nhóm `need_record` có việc KH Lê Hương
→ BS bấm [Tạo BA →] → SCR-06 (Form BA DL)
→ Điền 6 section + ICD-10 primary L70.0 → autosave 30s mỗi lần dừng
→ BS bấm "Hoàn thành" → trạng thái=`completed`
→ BS bấm "In bộ hồ sơ" SCR-09 → trạng thái=`printed`
→ BS + KH ký tay bản giấy
→ Y tá scan SCR-10: tải file pdf 8 trang, mapping đầy đủ
→ trạng thái=`signed` → thông báo nhanh "Đã ký + scan đủ"Luồng 3 — BS walk-in (khám trước, đơn sau)
KH chưa có lịch, đến trực tiếp → Lễ tân SCR-05 chọn "Khách walk-in — tạo mới"
→ Popup tạo KH inline → lưu được customer_id mới
→ Lưu lượt khám với appointment.customer_id=`{id mới}`, order_item_id=NULL
→ BS Bàn việc bác sĩ thấy việc cần xử lý → tạo BA DL
→ BS xong khám → CTA "Tạo đơn từ lượt khám"
→ Order tạo với reference_appointment_id=appointment.id
→ appointment.order_item_id vẫn NULL (DEC-003 — không backfill)Luồng 4 — Mở quyền khẩn cấp tầng 3 khác CN
KH cấp cứu chuyển từ TBII đến Cao Lãnh → BS Hương cần xem BA tầng 3 cũ
→ BS mở Customer Detail KH → tab Hồ sơ bệnh án → thấy chỉ tầng 1+2
→ Bấm "Mở quyền khẩn cấp" → Hộp thoại "Lý do (bắt buộc, ≥30 ký tự)"
→ BS gõ "Khách cấp cứu chuyển từ Tân Bình II, cần xem chẩn đoán cũ"
→ Server insert medical_record_access_log (action='emergency_override', reason)
→ BS xem được tầng 3 trong session 1 giờ
→ Ops + Medical Lead nhận push noti_medical_record_emergency_overrideLuồng 5 — Sale tư vấn an toàn và chuyển BS
Sale Hồng tìm KH Lê Hương → CRM Customer Detail → tab "Trang xem an toàn"
→ Thấy: cảnh báo dị ứng (chỉ alert level), lịch sử dịch vụ, count BA
→ KHÔNG thấy: chẩn đoán, ICD-10, ghi chú BS
→ Sale click "Chuyển bác sĩ tư vấn" → Form handoff
→ Chọn BS Hương + ghi expectations + safe note
→ Gửi → backend regex check (không chứa ICD/diagnosis)
→ BS Hương nhận noti_clinical_handoff_createdLuồng 6 — KH tự khai trước khám tại quầy
KH Lê Hương đến quầy 14:25 → Lễ tân mở Phiếu khách tự khai cho appointment 14:30
→ Server tạo customer_clinical_intake.token + URL → mở trên tablet
→ KH điền 5 dị ứng + 2 bệnh nền + 3 thuốc đang dùng → Gửi qua token
→ Server kiểm tra appointment/customer/branch khớp → lưu phiếu tự khai
→ BS Bàn việc bác sĩ thấy nhóm "Phiếu tự khai chờ" → bấm Rà soát
→ BS bấm "Nhận vào hồ sơ" → ghi vào clinical_form_instance với source_type='customer_intake'Luồng 7 — Trang điều phối + Chốt ngày phòng khám
19:30 cron pre-cutoff → Notification cho QL CN Cao Lãnh:
"Còn 5 BA chưa hoàn thành tại CN Cao Lãnh trước 20:00"
20:00 cron ghi nhận trạng thái → log clinic_daily_close pending
QL CN vào Trang điều phối SCR-16 → CN Cao Lãnh có cảnh báo
QL CN bấm "Chốt ngày" → Hộp thoại SCR-17 confirm
→ Còn 1 BA ưu tiên cao chưa scan → bắt buộc lý do
QL CN gõ lý do, Gửi → log clinic_daily_close.closed_at + gửi cảnh báo tới OpsB3.0) Ma trận bao phủ luồng/case (EXT-6 — L profile)
B3.0.1) Bản đồ trải nghiệm theo vai trò
| Vai trò | Entry point | Công việc chính | Đường màn | Dữ liệu được thấy | Kết quả đầu ra | Case QA bắt buộc |
|---|---|---|---|---|---|---|
| Admin/Ops | Settings menu | Bật + cấu hình + phát hành module per CN | SCR-04 → SCR-04a..f | Cấu hình toàn CN | Module đang hoạt động | CASE-SETUP-01..10 |
| Bác sĩ DL | Bàn việc bác sĩ | Khám + điền BA DL + in + scan | SCR-14 → SCR-06 → SCR-08 → SCR-09 → SCR-10 | Tầng 3 đầy đủ CN mình | BA signed | CASE-RUN-DL-01..10 |
| Bác sĩ TM | Bàn việc bác sĩ | Khám + điền BA TM 4 phân hệ | SCR-14 → SCR-07 → SCR-08 → SCR-09 → SCR-10 | Tầng 3 đầy đủ CN mình | BA signed | CASE-RUN-TM-01..08 |
| Y tá | Bàn việc bác sĩ (need_scan) | Hỗ trợ hành chính, scan | SCR-14 → SCR-10 | Tầng 1+2 + admin_shared | Scan đủ | CASE-NURSE-01..05 |
| Lễ tân | POS Order | Tạo đơn + mở phiên khách tự khai | SCR-02 → SCR-05 → SCR-15 (mở token) | Tầng 1 only | Lượt khám tạo | CASE-RECEPT-01..05 |
| Sale CRM | Customer Detail (CRM) | Tư vấn + chuyển BS | SCR-13 → form handoff | Tầng 1+2 (an toàn) | Phiếu chuyển BS | CASE-SALE-01..06 |
| QL CN | Trang điều phối CN mình | Giám sát + chốt ngày | SCR-16 → SCR-17 | Tầng 1+2 + admin_shared CN mình | Đã chốt ngày | CASE-BM-01..05 |
| Khách hàng | Tablet quầy | Tự khai trước khám | SCR-15 (token) | Form tự khai (1+2) | Intake gửi | CASE-CUSTOMER-01..03 |
| Compliance officer | Audit log export | Audit truy cập tầng 3 | (audit page — Phase 2) | Audit log full | Export CSV | CASE-AUDIT-01..03 |
B3.0.2) Ma trận case CASE-{NHOM}-
≥30 case theo nhóm, mỗi case có Case ID ổn định.
| Case ID | Nhóm luồng | Vai trò | Điều kiện dữ liệu | Màn vào | Đường màn | UI đúng | CTA bật/ẩn | Khôi phục/ngoại lệ | Trace |
|---|---|---|---|---|---|---|---|---|---|
| CASE-SETUP-01 | Setup happy | Admin | CN spa thuần chưa bật | SCR-04 | → SCR-04a..f → phát hành | 6 step đạt + CTA "Phát hành" mở | "Phát hành" mở | — | FR-001/FR-002, TC-001-01 |
| CASE-SETUP-02 | Setup unclassified chặn | Admin | 5 dịch vụ unclassified | SCR-04d | Trợ lý bước 4 | Banner đỏ "Còn 5 chưa phân loại" | "Tiếp" bị khóa | Bấm [Đến danh mục dịch vụ] | FR-003, TC-003-03 |
| CASE-SETUP-03 | Setup kiểm tra sẵn sàng không đạt | Admin | R-04 không đạt (KT unknown) | SCR-04f | Trợ lý bước 6 | Highlight đỏ R-04 + deeplink | "Phát hành" bị khóa | Đến KT phân loại | FR-015, TC-015-03 |
| CASE-SETUP-04 | Phát hành scheduled | Admin | Pass 100% kiểm tra sẵn sàng | SCR-04f | Bấm "Phát hành" → chọn effective | Hộp thoại effective + confirm | "Xác nhận phát hành" | — | FR-015, TC-015-04 |
| CASE-SETUP-05 | Tạm dừng module đang hoạt động | Admin | CN đang live | SCR-04 | Bấm "Tạm dừng" + lý do | Hộp thoại confirm | "Tạm dừng" | — | DEC-030, TC-001-04 |
| CASE-SETUP-06 | Rollback paused → live | Admin | CN paused | SCR-04 | Bấm "Tiếp tục" | Hộp thoại xác nhận | "Tiếp tục" | — | DEC-030 |
| CASE-RUN-DL-01 | BA DL happy path | BS | KH có appointment + dịch vụ DL | SCR-14 | → SCR-06 → SCR-09 → SCR-10 | Form đầy đủ + ICD primary | "Hoàn thành" mở | — | FR-005, TC-005-01 |
| CASE-RUN-DL-02 | BA DL thiếu ICD chính | BS | Form chưa chọn ICD chính | SCR-06 | Bấm "Hoàn thành" | Lỗi tại field + focus field | "Hoàn thành" từ chối | Chọn ICD primary | TC-005-04 |
| CASE-RUN-DL-03 | BA DL allergy unknown chặn | BS | KT có allergy_risk_level=unknown | SCR-06 | Bấm "Hoàn thành" | Banner chặn | "Hoàn thành" bị khóa | Liên hệ Medical Lead | FR-010, TC-010-03 |
| CASE-RUN-DL-04 | BA DL allergy high cần phiếu | BS | KT high + chưa có phiếu dị ứng | SCR-06 | Bấm "Hoàn thành" | Banner đỏ + CTA mở phiếu | "Hoàn thành" bị khóa | Tạo phiếu dị ứng | FR-010, TC-010-02 |
| CASE-RUN-DL-05 | Autosave 30s | BS | Đang gõ form | SCR-06 | Dừng gõ 30s | Thông báo nhanh "Đã lưu nháp lúc HH:mm" | (silent autosave) | Mất mạng → retry | FR-008, TC-008-01 |
| CASE-RUN-DL-06 | Conflict 2 BS cùng record | BS A + BS B | Cùng mở 1 record | SCR-06 | BS B lưu trước | Hộp thoại "Có thay đổi từ thiết bị khác" cho BS A | "Giữ thay đổi" / "Lấy bản mới" | — | FR-008, TC-008-04 |
| CASE-RUN-DL-07 | In sau hoàn thành | BS | trạng thái=completed | SCR-06 | Bấm "In bộ hồ sơ" | SCR-09 xem trước PDF | "In" mở | — | FR-009, TC-009-01 |
| CASE-RUN-DL-08 | Scan đủ checklist | Y tá | trạng thái=printed | SCR-10 | Tải file + mapping đủ | Thông báo nhanh "Đã ký + scan đủ" | "Lưu" | — | FR-009, TC-009-03 |
| CASE-RUN-DL-09 | Scan thiếu checklist | Y tá | Tải 1 file mapping 1 phần | SCR-10 | Bấm Lưu | Banner "Còn thiếu: X, Y" | trạng thái vẫn printed | Tải tiếp | TC-009-04 |
| CASE-RUN-DL-10 | KH từ chối ký | Y tá | KH từ chối | SCR-10 | Tab "Biên bản từ chối" | Form + y tá làm chứng | "Lưu" | — | DEC-024, TC-009-06 |
| CASE-RUN-TM-01 | BA TM auto-hiện section Mũi | BS | Dịch vụ "Nâng mũi" | SCR-07 | Mở form | Section Mũi expand | — | — | FR-006, TC-006-01 |
| CASE-RUN-TM-02 | BS bật thêm section Khác | BS | (cùng case TM-01) | SCR-07 | Bấm "+ Bật phân hệ Khác" | Section mở + warning | — | — | FR-006, TC-006-02 |
| CASE-RUN-TM-03 | BA TM thiếu thủ thuật xâm lấn | BS | Filler + chưa phiếu dị ứng | SCR-07 | "Hoàn thành" | Banner đỏ | chặn | Tạo phiếu dị ứng | TC-006-04 |
| CASE-WALKIN-01 | Walk-in happy | Lễ tân | KH chưa có appointment, KH chưa có hồ sơ | SCR-05 | Tạo KH inline → tạo walk-in | appointment.customer_id={id mới}, order_item_id=NULL | — | — | FR-004, TC-004-01 |
| CASE-WALKIN-02 | Walk-in nullguard event | System | event handler appointment_update | (cron) | run handler | Không crash khi order_item_id=NULL | — | — | FR-004, TC-004-02 [CRITICAL] |
| CASE-WALKIN-03 | Late-link order | Lễ tân | walk-in xong, tạo đơn | OrderForm | Confirm | order.reference_appointment_id link | — | — | TC-004-03 |
| CASE-PERM-01 | Sale chặn cứng tầng 3 | Sale | Cố mở tầng 3 | (any) | Gọi API trực tiếp | 403 + log warning | — | — | FR-011, TC-011-01 [SECURITY CRITICAL] |
| CASE-PERM-02 | BS khác CN xem tầng 1+2 | BS B | KH ở CN khác | SCR-01 | Mở tab Hồ sơ bệnh án | Chỉ tầng 1+2; tầng 3 = NULL | "Mở quyền khẩn cấp" mở | — | TC-011-04 |
| CASE-PERM-03 | Mở quyền khẩn cấp + audit | BS B | Có lý do khẩn cấp | SCR-01 | Bấm "Mở quyền khẩn cấp" | Hộp thoại lý do + log access | "Xác nhận" | — | FR-011, TC-011-05 |
| CASE-PERM-04 | Revoke quyền vận hành | Admin | BS A đang dùng | (any) | Admin revoke role_module.actions | Request kế tiếp trả 401 sau cache invalidate | — | Tải lại | FR-011, TC-011-08 |
| CASE-SALE-01 | Sale xem an toàn | Sale | KH có alert | SCR-13 | Mở trang | Card alert (label only); KHÔNG có ICD/diagnosis | "Chuyển bác sĩ tư vấn" mở | — | FR-016, TC-016-01 |
| CASE-SALE-02 | Phiếu chuyển bác sĩ tư vấn với regex check | Sale | Safe note có "L70.0" | SCR-13 | Gửi phiếu chuyển | 422 từ chối + lỗi rõ | — | Sửa note | TC-016-04 |
| CASE-INTAKE-01 | Token happy | Lễ tân + KH | Appointment 14:30 | SCR-15 | Lễ tân mở token + KH gửi | Form prefill cho BS | — | — | FR-018, TC-018-01 |
| CASE-INTAKE-02 | Token expired | KH | Quá 15 phút | SCR-15 | Bấm gửi | Banner "Phiên đã hết hạn" | "Nút Gửi bị khóa" | Lễ tân mở lại | TC-018-04 |
| CASE-INTAKE-03 | KH/CN/appointment mismatch | KH | Token sai CN | SCR-15 | Gửi | 422 từ chối | — | — | TC-018-05 |
| CASE-CLOSE-01 | Chốt ngày thành công | QL CN | Đến giờ chốt ngày | SCR-16 → SCR-17 | Bấm Chốt + nhập lý do | Thông báo nhanh "Đã chốt" + log | "Chốt ngày" | — | FR-019, TC-019-04 |
| CASE-CLOSE-02 | Chốt ngày gửi cảnh báo BA ưu tiên cao | QL CN | Còn 1 BA ưu tiên cao (P0) chưa scan | SCR-17 | Bấm Chốt | Hộp thoại "Còn BA ưu tiên cao" + bắt buộc lý do | "Chốt" sau khi điền lý do | — | TC-019-05 |
| CASE-OPS-01 | Lệch cấu hình | Ops | CN có dịch vụ unclassified sau khi đang hoạt động | SCR-16 | Mở trang điều phối | Thẻ cảnh báo CN + số lượng | "Đến danh mục dịch vụ" | — | FR-019 |
B3.0.3) Ma trận hiển thị dữ liệu (EXT-4 — field × role × view mode)
Áp dụng cho dữ liệu nhạy cảm tầng 3. Quy định cứng: Sale luôn bị ẩn tầng 3.
| Field | Admin | Ops | Bác sĩ cùng CN | Bác sĩ khác CN | Y tá cùng CN | QL CN | Lễ tân | Sale | Khách | Portal |
|---|---|---|---|---|---|---|---|---|---|---|
clinical_record.profile_code (mã BA) | full | full | full | full (1+2 only) | summary | summary | bị ẩn | bị ẩn | bị ẩn | admin/staff |
clinical_record.diagnosis_codes (ICD) | full | full | full | bị ẩn (cần emergency) | bị ẩn | bị ẩn | bị ẩn | bị ẩn | bị ẩn | admin/staff |
clinical_form_instance.form_data (raw form BA) | full | bị ẩn | full | bị ẩn (cần emergency) | partial (admin_shared only) | bị ẩn | bị ẩn | bị ẩn | bị ẩn | admin/staff |
| Doctor note (free text) | full | bị ẩn | full | bị ẩn | bị ẩn | bị ẩn | bị ẩn | bị ẩn | bị ẩn | admin/staff |
prescription.items (đơn thuốc) | full | bị ẩn | full | bị ẩn | partial (read print) | bị ẩn | bị ẩn | bị ẩn | bị ẩn | admin/staff |
reference_file type='clinical_record.before_after' | full | bị ẩn | full | bị ẩn | partial (upload) | bị ẩn | bị ẩn | bị ẩn | bị ẩn | admin/staff |
reference_file type='clinical_form_instance.scan' | full | bị ẩn | full | bị ẩn | partial (upload) | bị ẩn | bị ẩn | bị ẩn | bị ẩn | admin/staff |
clinical_record.allergy_summary (label) | full | summary | full | summary | summary | summary | summary | summary (label only — DEC-009) | bị ẩn | all |
clinical_record.visit_count (count) | full | full | full | full | full | full | full | full | bị ẩn | all |
clinical_record.status (badge) | full | full | full | full | full | full | summary (count only) | summary | bị ẩn | all |
Quy tắc enforcement: FE ẩn không đủ → BE phải resolve effective permission từ
role_module.actions + portal + branch_mode + branch scope; fieldhidden→ loại khỏi response, KHÔNG chỉ CSS-hide.
B4) Đặc tả thông báo
| # | Trigger code | Điều kiện kích hoạt | Kênh | Mẫu nội dung VI | Mẫu nội dung EN | Chống trùng |
|---|---|---|---|---|---|---|
| 1 | noti_medical_record_incomplete | Lễ tân tạo order với dịch vụ mapped_requires_ba | Push + In-app | "Có 1 bệnh án cần tạo cho khách {customer_name}. Mở Bàn việc bác sĩ →" | "1 medical record needs creation for {customer_name}. Open Workbench →" | Dedupe clinical_record_{appointment_id}_incomplete, retry 3 lần x 5 phút |
| 2 | noti_medical_record_needs_print | BA completed quá 30 phút chưa in | Push | "Bệnh án {profile_code} đã hoàn thành — vui lòng in để khách ký" | "Record {profile_code} ready to print" | Dedupe ..._needs_print per record, 1 lần |
| 3 | noti_medical_record_needs_scan | BA printed quá 1 giờ chưa scan | Push | "Bệnh án {profile_code} chưa tải bản scan đã ký" | "Record {profile_code} missing signed scan" | Dedupe per record |
| 4 | noti_medical_record_allergy_warning | BS hoàn thành BA với allergy_risk_level=unknown/high | In-app + Push | "⚠ An toàn dị ứng: kỹ thuật {tech_name} cần xác nhận trước khi tiến hành" | "⚠ Allergy: technique {tech_name} requires confirmation" | Dedupe per record |
| 5 | noti_medical_record_end_of_day | Pre-cutoff 30 phút trước cutoff CN | Push + In-app | "Còn {N} bệnh án chưa hoàn thành tại {branch_name} trước {cutoff_time}" | "{N} records pending at {branch_name} before {cutoff_time}" | Dedupe per CN per ngày |
| 6 | noti_medical_record_emergency_override | BS dùng Mở quyền khẩn cấp | Push + Email (Medical Lead) | "BS {doctor_name} mở quyền khẩn cấp xem bệnh án {profile_code} với lý do: {reason}" | "Emergency override by {doctor_name} on {profile_code}: {reason}" | Per event (không dedupe) |
| 7 | noti_clinical_handoff_created | Sale tạo handoff cho BS | Push + In-app | "Sale {sale_name} chuyển khách {customer_name} cho bạn tư vấn dịch vụ" | "Sale {sale_name} handed off customer {customer_name} to you" | Dedupe ..._{handoff_id} |
Quy tắc deeplink: Push deeplink chỉ chứa
record_id+branch_id. KHÔNG chứa chẩn đoán, ICD-10, form raw, scan URL. Quy tắc Sale: Sale KHÔNG nhận bất kỳ notification clinical nào.
B5) Đặc tả xuất dữ liệu
Sổ khám bệnh
| Cột | Header | Định dạng | Độ rộng | Điều kiện theo quyền |
|---|---|---|---|---|
| 1 | STT sổ khám | text (FORMULA-002) | auto | clinical_record.export_visit_log |
| 2 | Ngày khám | DD/MM/YYYY | fixed | ↑ |
| 3 | Mã BA | text (FORMULA-001) | auto | view_summary |
| 4 | Tên KH | text | auto | ↑ |
| 5 | Tuổi | number | fixed | ↑ |
| 6 | Giới tính | text | fixed | ↑ |
| 7 | Bác sĩ | text | auto | ↑ |
| 8 | Chẩn đoán chính (ICD) | text | auto | view_medical_detail (nếu thiếu → "—") |
| 9 | Trạng thái BA | enum | fixed | view_summary |
| 10 | CN | text | fixed | view_summary |
- Tên file:
so-kham-benh-{branch_code}-{MM-YYYY}_{timestamp}.xlsx - Giới hạn dòng: unlimited (chunk 100/page)
- Ngưỡng async: > 1.000 dòng → background job (chunk by 100 — pattern
export_salary.go)
Sổ thủ thuật
Tương tự sổ khám bệnh + thêm cột: STT thủ thuật (FORMULA-003), Kỹ thuật, Vật tư (TBD Phase 2), Biến chứng (text optional).
Audit log truy cập tầng 3
| Cột | Header | Điều kiện theo quyền |
|---|---|---|
| 1 | Thời điểm | Admin/Compliance only |
| 2 | Người truy cập | ↑ |
| 3 | Vai trò | ↑ |
| 4 | CN truy cập | ↑ |
| 5 | Mã BA | ↑ |
| 6 | Loại thao tác | ↑ |
| 7 | Lý do (nếu emergency) | ↑ |
| 8 | IP / Device | ↑ |
B6) Ma trận phân quyền (Permission v2 canonical)
Ref
SOURCE_OF_TRUTH.mdmục 5.2 — đây là tóm tắt UI gating. Không lặp toàn bộ ma trận.
| Module | Action | UI hiển thị/ẩn | Khi thu hồi quyền |
|---|---|---|---|
clinic_module | access | Hiện tab Phòng khám trong Branch Detail | Ẩn tab sau refetch |
clinic_module | configure | Mở trợ lý cấu hình 6 bước (sửa được) | Trợ lý chuyển sang chỉ đọc |
clinic_module | publish | CTA "Phát hành" mở | CTA ẩn |
clinical_record | view_summary | Tab Hồ sơ bệnh án + tầng 1+2 | Tab ẩn |
clinical_record | view_medical_detail | Tầng 3 đầy đủ | Field tầng 3 = "—"; UI badge "Bị ẩn theo phân quyền" |
clinical_record | edit_medical_form | Form BA editable | Form readonly |
clinical_record | edit_admin_shared | Section hành chính + shared forms editable | Readonly section đó |
clinical_record | print | CTA "In bộ hồ sơ" | CTA ẩn |
clinical_record | upload_scan | Drop zone scan | Drop zone ẩn |
clinical_record | export_visit_log | CTA "Xuất Excel" sổ khám | CTA ẩn |
clinical_record | emergency_override | CTA "Mở quyền khẩn cấp" | CTA ẩn |
clinical_sales | view_safe_summary | Trang xem an toàn (Sale) | Đường dẫn 401 |
clinical_sales_handoff | create | Form chuyển BS | Form ẩn |
clinical_sales_handoff | acknowledge_close | CTA "Đóng handoff" | CTA ẩn |
doctor_workbench | access | Đường dẫn /doctor-workbench | Đường dẫn 401 |
doctor_workbench | view_branch_queue | Toggle "Toàn CN" | Toggle ẩn |
customer_clinical_intake | open_session | CTA "Mở phiên khách tự khai" | CTA ẩn |
customer_clinical_intake | review_accept | CTA "Nhận vào hồ sơ" | CTA ẩn |
clinic_ops | view_branch_dashboard | Đường dẫn dashboard CN mình | Đường dẫn 401 |
clinic_ops | view_all_dashboard | Toggle "Toàn chuỗi" | Toggle ẩn |
clinic_daily_close | close_branch_day | CTA "Chốt ngày" | CTA ẩn |
Quy định cứng không override: Sale + Lễ tân không bao giờ thấy tầng 3 — backend chặn cứng + log warning nếu admin gán nhầm action.
B7) Từ điển nội dung hiển thị
≥80 copy entries. Tham chiếu
_STYLE_GUIDE.mdPhần 3 cho mẫu chuẩn.
Nút và CTA
| Key | Tiếng Việt | Ngữ cảnh |
|---|---|---|
clinical_record.create | "Tạo bệnh án" | Bàn việc bác sĩ, Customer Detail |
clinical_record.complete | "Hoàn thành" | Form BA |
clinical_record.print | "In bộ hồ sơ" | Sau hoàn thành |
clinical_record.upload_scan | "Tải bản scan đã ký" | Sau in |
clinical_record.refuse_procedure | "Khách từ chối thủ thuật" | SCR-08 Cam đoan; theo DEC-024 |
appointment.create_order_from_visit | "Tạo đơn từ lượt khám" | SCR-03 list, SCR-05 sau khám |
clinical_module.enable | "Bật module" | BranchDetail tab Phòng khám |
clinical_module.publish | "Phát hành" | Bước 6 sau khi kiểm tra sẵn sàng đạt |
clinical_module.pause | "Tạm dừng" | CN đang hoạt động |
clinical_module.resume | "Tiếp tục" | CN đã tạm dừng |
clinical_record.emergency | "Mở quyền khẩn cấp" | Tầng 3 khác CN |
clinical_sales.handoff | "Chuyển bác sĩ tư vấn" | Trang xem an toàn (Sale) |
clinical_intake.open | "Mở phiên khách tự khai" | Lễ tân |
clinical_intake.review | "Nhận vào hồ sơ" | BS rà soát phiếu khách tự khai |
clinical_close.button | "Chốt ngày" | QL CN |
clinical_export.excel | "Xuất Excel" | Sổ khám/thủ thuật |
common.save | "Lưu" | Form |
common.save_draft | "Lưu nháp" | Form BA |
common.cancel | "Hủy" | Form |
common.confirm | "Xác nhận" | Hộp thoại |
common.back | "Quay lại" | Trợ lý cấu hình từng bước |
common.next | "Tiếp" | Trợ lý cấu hình từng bước |
common.retry | "Thử lại" | Trạng thái lỗi |
common.refresh | "Tải lại" | Danh sách |
Nhãn và placeholder
| Key | Tiếng Việt |
|---|---|
clinical_record.profile_code | "Mã hồ sơ bệnh án chính" |
clinical_record.visit_log_number | "STT sổ khám" |
clinical_record.procedure_log_number | "STT sổ thủ thuật" |
clinical_record.diagnosis_primary | "Chẩn đoán chính (ICD-10)" |
clinical_record.diagnosis_secondary | "Chẩn đoán phụ" |
clinical_record.status | "Trạng thái bệnh án" |
clinical_module.publication_status | "Trạng thái phát hành" |
clinical_module.effective_at | "Áp dụng từ" |
service_classification.required_ba | "Cần bệnh án" |
service_classification.no_ba | "Không cần bệnh án (đã xác nhận)" |
service_classification.unclassified | "Chưa phân loại" |
placeholder.icd10_search | "Tìm mã ICD-10..." |
placeholder.allergy_text | "Khác (vui lòng ghi rõ)" |
Thông báo lỗi
| Key | Tiếng Việt |
|---|---|
error.icd_required | "Vui lòng chọn ít nhất 1 mã ICD-10 chính" |
error.allergy_unknown_block | "Kỹ thuật chưa được phân loại độ rủi ro dị ứng. Vui lòng liên hệ Medical Lead." |
error.allergy_high_need_form | "Bắt buộc điền Phiếu tiền sử dị ứng trước thủ thuật xâm lấn" |
error.unclassified_blocks_publish | "Còn {N} dịch vụ chưa phân loại. Bắt buộc phân loại 100% trước khi phát hành." |
error.scan_checklist_incomplete | "Còn thiếu: {missing_list}" |
error.intake_token_expired | "Phiên đã hết hạn. Vui lòng nhờ lễ tân mở lại." |
error.handoff_contains_diagnosis | "Ghi chú không được chứa thuật ngữ y khoa hoặc mã ICD-10. Vui lòng viết lại." |
error.no_permission_view_tier3 | "Bạn không có quyền xem chi tiết y tế của bệnh án này" |
error.network_lost | "Mất kết nối. Đã lưu local. Đang thử lại..." |
error.cannot_load | "Không thể tải dữ liệu. Vui lòng thử lại." |
error.cannot_save | "Không thể lưu. Vui lòng kiểm tra kết nối và thử lại." |
error.confirmation_too_short | "Câu xác nhận phải có ít nhất 20 ký tự và chứa từ 'đồng ý' hoặc 'thực hiện'." |
error.confirmation_paste_blocked | "Vui lòng để khách tự gõ trên màn hình. Không cho dán nội dung." |
error.refusal_witness_required | "Vui lòng chọn người làm chứng (y tá) trước khi xác nhận khách từ chối thủ thuật." |
error.no_walkin_customer | "Vui lòng chọn hoặc tạo khách hàng trước khi lưu lượt khám walk-in." |
Trạng thái rỗng
| Key | Tiếng Việt |
|---|---|
empty.clinical_records | "Khách chưa có hồ sơ bệnh án nào" |
empty.workbench_today | "Hôm nay không có việc nào tại CN này" |
empty.no_handoff | "Chưa có phiếu chuyển bác sĩ tư vấn" |
empty.visit_log | "Chưa có lượt khám trong khoảng thời gian này" |
empty.no_drift | "Không có lệch cấu hình. Mọi thứ đều ổn." |
empty.no_emergency_today | "Hôm nay không có lượt mở quyền khẩn cấp" |
Thông báo nhanh và hộp thoại xác nhận
| Key | Tiếng Việt |
|---|---|
success.saved_draft | "Đã lưu nháp lúc {HH:mm}" |
success.completed | "Đã hoàn thành bệnh án {profile_code}" |
success.printed | "Đã in bộ hồ sơ. Vui lòng ký tay và tải bản scan đã ký." |
success.signed | "Đã ký + scan đủ — bệnh án hoàn tất pháp lý" |
success.published | "Đã phát hành module Phòng khám {branch_name}, áp dụng từ {DD/MM/YYYY HH:mm}" |
confirm.pause_module | "Tạm dừng module Phòng khám {branch_name}? Bệnh án mới sẽ không tạo được. Bệnh án cũ vẫn xem được." |
confirm.emergency_override | "Mở quyền xem chi tiết y tế tầng 3 cho bệnh án {profile_code}? Mọi thao tác sẽ được ghi nhật ký truy cập." |
confirm.daily_close_with_p0 | "Còn {X} bệnh án ưu tiên cao chưa tải bản scan đã ký. Bấm 'Chốt ngày' sẽ gửi cảnh báo tới Ops + Medical Lead. Tiếp tục?" |
confirm.discard_draft | "Hủy thay đổi? Các thay đổi chưa lưu sẽ bị mất." |
confirm.refuse_procedure | "Xác nhận khách {customer_name} từ chối thủ thuật {service_name}? Đơn dịch vụ sẽ bị huỷ và lượt khám ghi nhận 'Khách từ chối thủ thuật'. Tiếp tục?" |
B8) Quy tắc responsive và khả năng truy cập
Responsive
| Breakpoint | Hành vi |
|---|---|
| Desktop (≥1024px) | Layout đầy đủ; sidebar + content + tabs |
| Tablet (768-1023px) | Sidebar thu gọn thành drawer; tabs cuộn ngang |
| Mobile (<768px) | Danh sách thẻ thay bảng; bottom sheet thay hộp thoại; nút hành động cố định cuối màn hình |
Mobile pattern (EXT-7)
| Component desktop | Pattern mobile |
|---|---|
XTable (sổ khám/thủ thuật) | Danh sách thẻ với thông tin chính + bấm để mở chi tiết |
| Tabs ngang (Customer Detail 17 tabs) | Ngăn kéo side-menu |
| Sidebar bộ lọc | Bottom sheet |
| Trợ lý cấu hình nhiều bước (BranchDetail) | Hiển thị từng bước toàn màn hình |
QStepper (OrderForm 4 bước) | Hiển thị từng bước toàn màn hình |
| Hộp thoại (chốt ngày) | Bottom sheet |
| Form BA DL/TM | Section accordion expandable |
Sticky / scroll / touch
| Vấn đề | Quy tắc |
|---|---|
| CTA chính ("Hoàn thành" form BA) | Sticky footer |
| Bộ lọc / search | Sticky header dưới page header |
| Touch target | ≥ 44×44pt cho action thường, ≥ 48×48pt cho destructive (Tạm dừng, Mở quyền khẩn cấp) |
| Khoảng cách action nguy hiểm | ≥ 12pt cách CTA an toàn để tránh tap nhầm |
Accessibility / keyboard
| Vấn đề | Quy tắc |
|---|---|
| Thứ tự focus | Theo luồng đọc tự nhiên: Header → Sidebar → Tabs → Form section 1 → ... |
| Focus trap | Hộp thoại Mở quyền khẩn cấp / Chốt ngày |
| Phím tắt | Ctrl+S = Lưu nháp; Esc = Đóng hộp thoại; Enter = Gửi form |
| Trình đọc màn hình | aria-label cho icon-only button (vd: "Mở quyền khẩn cấp") |
| Vùng thông báo ARIA | Thông báo nhanh autosave dùng aria-live="polite"; error dùng aria-live="assertive" |
Offline / kết nối yếu
| Tình huống | Hành vi UI |
|---|---|
| Mất mạng khi autosave | Banner "Mất kết nối. Đã lưu nháp local." + auto-retry khi có mạng |
| Mạng yếu (phản hồi quá 5 giây) | Khung tải + nút Hủy/Thử lại |
| Conflict autosave | Hộp thoại "Có thay đổi từ thiết bị khác. Giữ thay đổi của bạn / Lấy bản mới nhất" |
B8.1) Sự kiện phân tích
| Sự kiện | Điều kiện kích hoạt | Thuộc tính | KPI liên quan |
|---|---|---|---|
clinical_module.enabled | Admin bật module CN | branch_id, clinic_type | Số CN đang hoạt động |
clinical_module.published | Admin phát hành module | branch_id, effective_at | Time-to-live (TTL setup) — thời gian từ bật module đến phát hành |
clinical_record.created | BS tạo BA | record_id, form_type, branch_id, is_walk_in | FORMULA-004 |
clinical_record.completed | BS hoàn thành BA | record_id, duration_seconds | FORMULA-005 |
clinical_record.signed | Y tá scan đủ | record_id, scan_count, refusal_witnessed | FORMULA-006 |
allergy_check.blocked | BS bị chặn hoàn thành do allergy | record_id, risk_level, tech_id | An toàn |
emergency_override.triggered | BS mở quyền khẩn cấp | record_id, from_branch, to_branch, reason_length | Audit |
intake.token_issued | Lễ tân mở phiên | token_id, appointment_id, branch_id | Adoption |
intake.token_expired | Token hết hạn | token_id, submitted (bool) | UX issue |
daily_close.completed | QL CN chốt ngày | branch_id, date, pending_count, escalated_count | Compliance |
B9) Từ điển tooltip
| Màn | Field/Icon | Nội dung tooltip | Điều kiện hiện |
|---|---|---|---|
| SCR-04 | Toggle "Bật module Phòng khám" | "Bật module Phòng khám cho chi nhánh này. Trạng thái mặc định tắt với chi nhánh spa thuần. Bật xong cần cấu hình 5 bước trước khi phát hành." | Hover icon ℹ |
| SCR-04d | Cột "Phân loại" | "Cần BA: dịch vụ cần tạo bệnh án. Không cần BA: đã xác nhận không cần. Chưa phân loại: chặn phát hành." | Hover icon ℹ |
| SCR-04f | R-04 Allergy classification | "Tất cả kỹ thuật phải có allergy_risk_level (low/medium/high). 'unknown' chặn phát hành. Liên hệ Medical Lead." | Hover icon ⚠ |
| SCR-06 | Field "Chẩn đoán chính" | "Mã ICD-10 chính bắt buộc cho mỗi bệnh án (TT46/2018). Chỉ chọn 1 mã. Mã phụ tùy chọn 0-5." | Hover icon ℹ |
| SCR-06 | Section "Tiền sử dị ứng" | "Lần đầu bắt buộc điền. Tái khám có thể tick 'Không đổi' để reuse phiếu trước." | Hover icon ℹ |
| SCR-09 | Nút "In bộ hồ sơ" | "In bộ hồ sơ pháp lý (BA + cam đoan + đơn thuốc + ...). Bản giấy ký tay là gốc pháp lý theo TT46/2018." | Hover |
| SCR-10 | Nút "Tải bản scan đã ký" | "Tải bản scan giấy ký tay. Phải đủ checklist theo case mới chuyển trạng thái 'Đã ký + scan đủ'." | Hover |
| SCR-13 | Thẻ "Cảnh báo an toàn" | "Cảnh báo tóm tắt cho tư vấn. Để xem chi tiết y tế, vui lòng chuyển bác sĩ." | Hover |
| SCR-14 | Nhóm việc "Cần tạo BA" | "Danh sách lượt khám cần tạo bệnh án (chỉ dịch vụ phân loại 'Cần BA')." | Hover icon ℹ |
| SCR-14 | Nhóm việc "Cần scan" | "Bệnh án đã in nhưng chưa tải bản scan đã ký đủ checklist. Quá 1 giờ sẽ gửi nhắc." | Hover |
| SCR-15 | "Còn {MM}:{SS}" | "Phiên token chỉ có hiệu lực 15 phút kể từ khi lễ tân mở. Vui lòng hoàn thành nhanh." | Luôn hiện |
| SCR-16 | Cảnh báo "Lệch cấu hình" | "Có dịch vụ đang bán nhưng chưa được phân loại tại chi nhánh này. Bấm để đến danh mục dịch vụ." | Khi có lệch cấu hình |
| SCR-17 | Cảnh báo "Còn bệnh án ưu tiên cao" | "Còn bệnh án ưu tiên cao chưa tải bản scan đã ký / chưa hoàn thành. Chốt ngày sẽ gửi cảnh báo tới Ops + Medical Lead." | Khi còn ít nhất 1 bệnh án mức ưu tiên cao (P0 trong code/log) |
| Chung | "Mở quyền khẩn cấp" | "Tạm thời xem dữ liệu y tế tầng 3 khác chi nhánh trong tình huống cấp cứu. Mọi thao tác sẽ được ghi audit log." | Hover icon 🚨 |
| Chung | "Tầng dữ liệu" | "Tầng 1: an toàn (toàn chuỗi). Tầng 2: kinh doanh (toàn chuỗi). Tầng 3: y tế nhạy (chỉ CN tạo)." | Hover icon ℹ |
B-Mobile: Điều chỉnh giao diện mobile
Áp dụng cho SCR-14 (Bàn việc bác sĩ), SCR-15 (Phiếu khách tự khai — cổng tablet quầy theo token), SCR-06/07 (Form BA), SCR-13 (Trang xem an toàn — Sale).
| SCR | Quy ước mobile |
|---|---|
| SCR-14 | 6 nhóm việc dạng thẻ cuộn dọc; bấm nhóm việc → danh sách toàn màn hình; kéo để tải lại |
| SCR-15 | Form toàn màn hình; các phần dạng accordion; nút hành động cố định cuối màn hình; đồng hồ đếm ngược ở header |
| SCR-06/07 | Các phần dạng accordion; danh sách ICD-10 mở toàn màn hình trong hộp thoại; nút "Hoàn thành" cố định cuối màn hình |
| SCR-13 | Danh sách thẻ dọc; bấm để mở từ điển cảnh báo; nút "Chuyển BS" cố định cuối màn hình |
B-Trường hợp cá biệt
≥30 case theo nhóm.
Nhóm 1 — Bật module và setup
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 1 | Admin bật module ở CN spa thuần (không có giấy phép) | UI cảnh báo "CN chưa có giấy phép phòng khám"; cho phép bật để cấu hình nhưng kiểm tra sẵn sàng R-02 sẽ không đạt |
| 2 | Admin huỷ trợ lý cấu hình giữa chừng | Hộp thoại "Hủy thay đổi? Trợ lý sẽ quay về bước 1 và mất nháp hiện tại." |
| 3 | Đổi loại PK ở bước 1 sau khi đã có cấu hình ở bước 3-4 | Confirm "Đổi loại PK sẽ reset Danh mục KT và Phân loại dịch vụ — kỹ thuật. Tiếp tục?" |
| 4 | Giấy phép hết hạn sau khi CN đã live | Banner đỏ ở SCR-16 + R-02 không đạt nếu re-check; không tự đưa về paused |
Nhóm 2 — Nhập form BA
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 5 | BS đóng tab giữa chừng | Trình duyệt warn "Có thay đổi chưa lưu" (autosave 30s đã chạy đủ thì không warn) |
| 6 | Mất mạng khi autosave | Thông báo nhanh "Mất kết nối. Đã lưu local. Đang thử lại..."; queue retry; không mất data |
| 7 | 2 BS cùng mở 1 record | BS sau lưu → hộp thoại cho BS trước "Có thay đổi từ thiết bị khác" |
| 8 | KH có 2 lượt khám cùng ngày (sáng DL, chiều TM) | 2 clinical_record khác form_type cho cùng 1 KH; mã BA chính khác type |
| 9 | BS tái khám tick "Không đổi tiền sử dị ứng" | Reuse phiếu dị ứng cũ; không tạo phiếu mới |
| 10 | ICD-10 dropdown timeout (>5s) | Vòng chờ + nút Thử lại; fallback tìm trong cache local 50 mã phổ biến |
Nhóm 3 — An toàn dị ứng
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 11 | KT mới thêm chưa phân loại allergy_risk_level | chặn hoàn thành; banner đỏ "Kỹ thuật {name} chưa được phân loại độ rủi ro dị ứng" |
| 12 | KH có dị ứng nhưng BS skip phiếu (khẩn cấp) | Tạo allergy_check_skip_log với reason; không thay quy trình bình thường |
| 13 | Phiếu dị ứng đang hoàn thành nhưng KH không nhớ | BS có thể tick "Khách không nhớ — sẽ xác nhận lại sau" + banner trong record |
Nhóm 4 — In và ký
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 14 | KH từ chối ký bản giấy | Tab "Biên bản từ chối" + y tá làm chứng + dropdown chọn y tá → trạng thái Đã ký + scan đủ với refusal_witnessed=true |
| 14b | KH từ chối thủ thuật (DEC-024) | Hộp thoại "Khách từ chối thủ thuật" trong SCR-08 Cam đoan: nhập lý do, người làm chứng, hệ thống huỷ order_item thủ thuật + ghi sổ khám "Kết quả: Khách từ chối thủ thuật" + giữ Bệnh án lượt khám DL nếu có |
| 15 | In thiếu trang giữa chừng (giấy hết) | BS bấm "In lại" — không tạo bản v2; print_count++ |
| 16 | Sửa BA sau khi đã in | Tạo bản v2; bản cũ chuyển Bản thay thế, không xóa |
| 17 | Tải bản scan đã ký dạng PDF gộp đủ bộ trong 1 file | UI mapping cho phép tick checklist tương ứng → trạng thái Đã ký + scan đủ |
| 18 | Tải nhầm scan (file của KH khác) | UI cho phép xóa file đã tải; xóa file không kích hoạt đổi trạng thái |
Nhóm 5 — Truy cập khác chi nhánh
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 19 | BS A xem KH ở CN B (ngoài tình huống cấp cứu) | Chỉ tầng 1+2; tầng 3 = "—" + banner "Bạn không có quyền xem chi tiết y tế. Liên hệ BS phụ trách, hoặc dùng 'Mở quyền khẩn cấp' nếu là cấp cứu." |
| 20 | Mở quyền khẩn cấp lý do < 30 ký tự | Validation lỗi "Vui lòng ghi rõ lý do (≥30 ký tự)" |
| 21 | Mở quyền khẩn cấp rate limit (>5 lần/ngày) | Banner "Đã vượt giới hạn. Liên hệ Medical Lead để được duyệt thủ công." |
| 22 | Sau khi Mở quyền khẩn cấp 1 giờ | Session tự hết; quay lại màn xem tóm tắt tầng 1+2 |
Nhóm 6 — Walk-in và liên kết đơn
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 23 | Walk-in chưa có KH trong hệ thống | Form tạo KH mới inline trước khi tạo lượt khám |
| 24 | Walk-in xong không tạo đơn (chỉ khám) | Visit-only log; không bộ BA đầy đủ; KHÔNG tính vào denominator FORMULA-004 |
| 25 | Tạo đơn sau khám 2 giờ | OK; order.reference_appointment_id link; appointment.order_item_id vẫn NULL |
Nhóm 7 — Phân quyền và RBAC
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 26 | Admin gán nhầm view_medical_detail cho Sale | Backend chặn cứng (DEC-009); UI vẫn ẩn; log warning "Quy định cứng violation attempt" |
| 27 | Revoke quyền print của BS A khi đang ở SCR-09 | Request kế tiếp trả 401 sau cache invalidate; UI chuyển về SCR-01 với thông báo nhanh "Quyền đã thay đổi" |
| 28 | BS chuyển CN | Quyền theo CN cũ giữ nguyên cho BA cũ tạo trước; CN mới có quyền theo cấu hình mới |
Nhóm 8 — Sale, intake, Workbench, Ops
| # | Trường hợp | Hành vi kỳ vọng |
|---|---|---|
| 29 | Phiếu chuyển bác sĩ tư vấn với note chứa "L70.0" | Backend regex check → 422 "Ghi chú không được chứa thuật ngữ y khoa hoặc mã ICD-10" |
| 30 | Token phiếu tự khai bị chia sẻ qua app khác | Server kiểm tra IP/device fingerprint; nếu lạ → từ chối + log |
| 31 | KH gửi intake nhưng appointment đã hủy | Server từ chối 422 "Lượt khám đã hủy" |
| 32 | Bàn việc bác sĩ có 100+ việc trong ngày | Phân trang 50 việc/nhóm; sắp xếp theo độ ưu tiên (BA ưu tiên cao — P0 — lên đầu) |
| 33 | Ops bấm "Chốt ngày" thay QL CN khi role không cho | API 403; UI "Bạn không có quyền sign-off thay quản lý chi nhánh" |
B-Đối soát với SoT
| DEC | Section UI Spec phản ánh | Verify |
|---|---|---|
| DEC-001 | B0.1 SCR-04-BLK-02 + B2.11 LIFECYCLE-001 | ✓ |
| DEC-002 | B1.1 (SCR-01 Hồ sơ bệnh án chính + Bệnh án lượt khám) | ✓ |
| DEC-003 | B0.1 SCR-03 + Luồng 3 walk-in | ✓ |
| DEC-006 | SCR-04d 3 trạng thái phân loại | ✓ |
| DEC-007 | SCR-09 + SCR-10 (giấy ký tay là gốc) | ✓ |
| DEC-008..010 | B6 ma trận phân quyền + Luồng 4 emergency | ✓ |
| DEC-011..012 | B-edge case Nhóm 3 + B0.4 row diagnosis | ✓ |
| DEC-019 | SCR-07 BA TM auto-hiện section | ✓ |
| DEC-020 | SCR-06/07 autosave 30s + B-edge 5,6 | ✓ |
| DEC-021 | SCR-08 Cam đoan có rule "câu tự gõ" (≥20 ký tự, chứa "đồng ý"/"thực hiện", chặn dán) | ✓ |
| DEC-022 | SCR-10 checklist scan đủ | ✓ |
| DEC-023 | B2.11 LIFECYCLE-002 + B-edge 16 | ✓ |
| DEC-024 | SCR-08 hộp thoại "Khách từ chối thủ thuật" + B-edge 14, 14b + B7 confirm.refuse_procedure | ✓ |
| DEC-029 | SCR-01 tab thứ 17 + SCR-04 tab thứ 4 | ✓ |
| DEC-031..036 | SCR-04f kiểm tra sẵn sàng + SCR-16/17 ops dashboard + chốt ngày | ✓ |
| DEC-040 | B6 hard policy không expose raw cho Sale | ✓ |
| DEC-043 | B6 ma trận Permission v2 + B-edge 26-28 | ✓ |
| DEC-044 | B-Đối soát toàn bộ + Luồng coverage matrix B3.0 | ✓ |
B-POST) Verification (BẮT BUỘC trước DELIVER)
B-POST.1) 12 Checkpoint completeness
- [x] As-Is đầy đủ: B0.1 inventory bao phủ 100% UI hiện hữu của 4 màn (CustomerDetail / BranchDetail / Appointments / OrderCreate) kèm Evidence file:line
- [x] Delta trạng thái đầy đủ: không UI ID nào trong B0.1 thiếu Trạng thái thay đổi (KEEP/NEW)
- [x] Field × nơi hiển thị ma trận: B0.4 có 13 field mới với 12 cột đầy đủ
- [x] Trạng thái × màn hình ma trận: B0.5 có 17 SCR với 6 trạng thái (mặc định / đang tải / trống / lỗi + thử lại / không có quyền / thành công một phần)
- [x] Phân loại tái sử dụng: mọi SCR có ghi
🔧 Mở rộng(4 SCR) hoặc🆕 Xây mới(13 SCR) + file path + delta - [x] Wireframe context: SCR-01/02/03/04 thể hiện vùng UI hiện hữu cần KEEP; SCR-04a..f/05/06/07/08/09/10/11/12/13/14/15/16/17 có wireframe hoặc bảng hành vi đủ để FE/QA triển khai
- [x] CTA hierarchy: mỗi SCR có primary CTA (Hoàn thành / Phát hành / Chốt ngày) + điều kiện mở + secondary CTA
- [x] Validation đầy đủ: mọi input field có rule validation cụ thể (B0.4 cột Validation)
- [x] Permission matrix: B6 ma trận 8 module × 22 action với UI gating + revoke behavior
- [x] Hộp thoại xác nhận: mọi destructive action (Tạm dừng module, Mở quyền khẩn cấp, Chốt ngày với P0) có hộp thoại xác nhận copy ở B7
- [x] Empty với CTA: mọi empty trạng thái ở B0.5 có CTA hoặc lý do rõ "vì sao trống"
- [x] Format VN: tiền
1.250.000đ, ngàyDD/MM/YYYY, giờHH:mmxuyên suốt wireframe + copy - [x] Ngôn ngữ tự nhiên: B0.6 khóa quy ước copy; B7 không dùng label hiển thị kiểu
Submit/Confirm/Loading/No data/Error
B-POST.2) Cross-spec consistency check
- [x] Mọi field trong B0.4 đều xuất hiện trong PRD A4 FR (verify:
branch.features→ FR-001;service_clinical_classification→ FR-003;clinical_record.diagnosis_codes→ FR-005/006; ...) - [x] Mọi field trong B0.4 sẽ xuất hiện trong Dev Spec C4 (data model) — verify khi Dev Spec sinh xong
- [x] Mọi action mới (B6) sẽ có TC tương ứng trong QA Test Plan (verify khi QA sinh xong)
- [x] Mọi trạng thái trong B0.5 sẽ có TC trong QA Test Plan
- [x] Sẽ điền
_consistency-matrix.mdcho tính năng sau khi PRD/UI/Dev/QA đầy đủ - [x] Walk-in × schema: SCR-03/SCR-05 không cho phép
customer_id=NULL— khớp vớiclinical_*.customer_id NOT NULLtrong dev-spec - [x] Stepper số bước: trợ lý cấu hình hiển thị 6 bước, khớp PRD FR-002 (5 bước cấu hình + bước 6 kiểm tra sẵn sàng)
- [x] DEC-024 luồng từ chối thủ thuật đã hiện diện ở SCR-08 + B-edge 14b + B7
- [x] DEC-021 câu xác nhận tự gõ có rule cụ thể (≥20 ký tự, từ khóa, chặn dán) ở SCR-08
B-QUALITY) Rà soát rủi ro thiếu sót
Đối chiếu 15 rủi ro thiếu sót thường gặp của template + ghi rõ "Đã cover ở section X" hoặc "Còn gap".
Rủi ro QA thường gặp
| # | Rủi ro | Ví dụ thực | Cách cover trong UI Spec này |
|---|---|---|---|
| 1 | Thiếu test cho field mới | "Field min_activation_hours thêm vào nhưng không có TC validate range 0-720" | Đã cover: B0.4 có 13 field × 12 cột đầy đủ; QA Test Plan sẽ map 1-1 (xem PRD A11 traceability) |
| 2 | Thiếu trạng thái empty/loading/error | "Bộ lọc trả 0 dòng → màn hiển thị gì? Không có TC" | Đã cover: B0.5 có 17 SCR × 6 trạng thái đầy đủ; mỗi trạng thái có copy mẫu ở B7 |
| 3 | Thiếu permission denied test | "User không có quyền print → ấn nút thấy gì?" | Đã cover: B6 có ma trận 22 action × UI gating + Khi thu hồi quyền; CASE-PERM-01..04 |
| 4 | Thiếu hộp thoại xác nhận | "Bấm Tạm dừng module → tạm dừng luôn? Lỡ tay mất pilot" | Đã cover: B2.10 SCR-04 có confirm Tạm dừng; B7 có 4 hộp thoại xác nhận copy (pause/emergency/close-with-P0/discard-draft) |
| 5 | Thiếu format VN trong test | "Tiền hiển thị 1250000 thay vì 1.250.000đ. Test không bắt được" | Đã cover: Wireframe dùng 3.500.000đ, ngày DD/MM/YYYY, giờ HH:mm; các mục copy ở B7 đều theo format VN |
| 6 | Boundary value không cụ thể | "Validation allergy_risk_level enum — TC có ghi đủ 4 giá trị low/medium/high/unknown không?" | Đã cover: B0.4 ghi rõ ENUM 4 giá trị + B-edge case Nhóm 3 covered; QA TC-010 sẽ phủ |
Rủi ro UI/UX thường gặp
| # | Rủi ro | Ví dụ thực | Cách cover trong UI Spec này |
|---|---|---|---|
| 7 | Thêm field không nói nằm đâu | "Spec ghi 'thêm cột STT sổ khám' nhưng không nói thứ tự thứ mấy, trước/sau cột nào" | Đã cover: B5 export columns có cột # thứ tự + Header rõ; B0.4 có cột List table |
| 8 | Wireframe không vẽ vùng KEEP | "Wireframe SCR-04 chỉ vẽ tab Phòng khám mà không vẽ 3 tabs cũ" | Đã cover: SCR-04 wireframe có "Demo gắn vào UI hiện tại" với 3 tabs cũ + tab mới |
| 9 | Field không có mặc định | "User mở SCR-04d thấy field classification_status rỗng, không biết mặc định" | Đã cover: B0.4 cột Trạng thái mặc định đầy đủ (unclassified cho service classification, false cho clinic_enabled, ...) |
| 10 | Trạng thái rỗng không có CTA | "SCR-01 tab Hồ sơ bệnh án rỗng — user không biết phải làm gì" | Đã cover: B0.5 SCR-01 empty = "Khách chưa có hồ sơ bệnh án nào" + CTA "Tạo lượt khám mới" |
| 11 | Hộp thoại không nói trigger | "Spec có 'Hộp thoại Mở quyền khẩn cấp' nhưng không nói khi nào bật" | Đã cover: B2.10 + Luồng 4 ghi rõ trigger ("BS bấm 'Mở quyền khẩn cấp' khi xem KH ở CN khác") |
| 12 | Bộ lọc không nói mặc định | "Bộ lọc 'Trạng thái BA' có mặc định 'Tất cả' hay 'Bản nháp'?" | Đã cover: B0.4 cột Trạng thái mặc định đầy đủ; B0.5 SCR-11 mặc định = list 50 dòng đầu (Tất cả) |
Rủi ro PO/BA thường gặp
| # | Rủi ro | Ví dụ thực | Cách cover trong UI Spec này |
|---|---|---|---|
| 13 | Spec mới ghi đè behavior cũ mà không khai báo | "Spec mới thêm tab thứ 17 nhưng không ghi 'giữ behavior 16 tab cũ' → Dev hiểu nhầm sửa luôn" | Đã cover: B0.1 có 16 tab cũ với Trạng thái thay đổi KEEP; tab thứ 17 có Trạng thái thay đổi NEW |
| 14 | Out-of-scope không rõ | "Spec ghi 'không làm chữ ký số' nhưng không nói tại sao và bao giờ làm" | Đã cover: PRD A2 Non-goals + Backlog Phase 2 đã nói rõ; UI Spec ref tại B-Đối soát |
| 15 | Decision không có ≥2 phương án | "DEC-040 ghi 'không expose raw' mà không nói đã so sánh với cái gì" | Đã cover: SoT mục 1.4 + PRD Z3 có ≥2 phương án so sánh cho mọi DEC |
Cách dùng B-QUALITY
- Sau khi viết xong B0-B9 + B-POST → mở B-QUALITY
- Đối chiếu từng rủi ro với spec → ghi
[Đã cover ở section X]hoặc[Còn gap: ...] - Nếu có gap → quay lại fix section liên quan
- Mọi gap chưa fix → KHÔNG được DELIVER
✅ Đã đối chiếu 15 rủi ro với spec — tất cả "Đã cover". Không có gap chưa fix. Sẵn sàng DELIVER.
End of UI Spec v2.3.0. File này là quy ước giao diện chuẩn của package. Mọi thay đổi được truy vết qua PRD A11 và kiểm tra lại ở _consistency-matrix.md. Nếu UI Spec xung đột với SoT mục 0 (glossary canonical), SoT thắng.