Appearance
Hồ sơ bệnh án — PRD v2.2.0
Phiên bản: 2.0.0 Ngày: 30/04/2026 Tác giả: PO/BA (Sơn Thọ) Loại: Tính năng mới Độ phức tạp: L Module: Phòng khám / CRM / POS / Clinical / Settings
Mục đích: chốt cam kết nghiệp vụ — phạm vi, quyết định, FR/AC, quy tắc, công thức, rủi ro ở mức PO/BA/TL/QA.
Đọc trước:
decision-brief.md→Tóm tắt điều hành→Z) Nhật ký quyết định→A4) Yêu cầu chức năng→A8) Công thức nghiệp vụ.Văn phong: theo
templates/_LANGUAGE_RULES.md+templates/_STYLE_GUIDE.md. Heading Việt-first; mỗi FR/AC trả lời đủ 6 yếu tố: vai trò + dữ liệu + điều kiện + hành động + kết quả + ngoại lệ.
Lịch sử thay đổi
| Phiên bản | Ngày | Tác giả | Thay đổi |
|---|---|---|---|
| 2.2.0 | 30/04/2026 | PO/BA + Security Lead | FR-011 hardening lớn: chuyển toàn bộ chi tiết phân quyền sang permission-spec.md v1.0.0 (canonical owner). FR-011 trong PRD chỉ giữ mô tả nghiệp vụ + AC cấp cao; các chi tiết catalog 22 action / default seed / branch_mode / portal / cache / migration / field masking / emergency governance / Compliance UI / 44 TC-PERM-* chuyển sang permission-spec.md P1-P12. SCR-18 Compliance Audit Viewer thêm vào ui-spec. Thêm 8 AC mới cho FR-011 (AC-011.13..20) trỏ về P12 test matrix. |
| 2.1.0 | 30/04/2026 | PO/BA | FR-007 hardening để khớp UI v2.2.0 + dev v2.1.0 + QA v2.1.0: (1) tách AC-007.4 thành AC-007.4.1/4.2/4.3/4.4 cover rule câu xác nhận tự gõ DEC-021 (≥20 ký tự, từ khoá, chặn dán, tốc độ gõ); (2) thêm AC-007.7.1..7.5 cho luồng "Khách từ chối thủ thuật" DEC-024 (huỷ order_item, ghi sổ "Khách từ chối thủ thuật", giữ BA DL, witness y tá, permission clinical_record.refuse_procedure + order.update, idempotency cho record đã in/ký). FR/DEC khác giữ nguyên. |
| 2.0.0 | 30/04/2026 | PO/BA | Refactor full theo glossary canonical 34 thuật ngữ + template po-ba-workflow mới (G3.7 cổng kiểm tra độ đầy đủ UI). Giữ 100% DEC/FR/AC nội dung từ v1.5.10. |
| 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 | Bằng chứng code/màn hình/config thật | Ưu tiên bằng chứng trước assumption |
decision-brief.md | Cửa vào package | Tóm tắt quyết định; PRD giữ quy ước chi tiết |
Quy tắc công thức: A8 (Công thức nghiệp vụ) là nguồn chuẩn;
dev-spec C3chỉ mô tả triển khai.
Hướng dẫn đọc
| Đối tượng | Section cần đọc |
|---|---|
| PO/BA | decision-brief.md → A0 → Z → A4 → A8 |
| Sếp / Business Lead | decision-brief.md → TL;DR → A0 → A2 |
| Tech Lead | decision-brief.md → A0 → Z → Dev Spec C1-C5 |
| UI/UX / FE | decision-brief.md → A4 → UI Spec |
| BE Dev | A4 / A8 → Dev Spec C1-C12 |
| QA | A4 → QA Plan D1-D5 |
Tóm tắt điều hành (TL;DR)
Phòng khám Diva (Da liễu + Phẫu thuật Thẩm mỹ) đang điền bệnh án bằng giấy tay, gây khó tra cứu khi thanh tra Sở YT, mất đồng bộ tiền sử khách giữa các chi nhánh và không có báo cáo lượt khám / thủ thuật theo ngày. PRD này khóa giải pháp số hóa hồ sơ bệnh án ngoại trú theo TT46/2018, TT51/2017, TT52/2017: tách clinical_profile (Hồ sơ bệnh án chính) và clinical_record (Bệnh án lượt khám), 7 biểu mẫu thực tế (BA DL/TM + 4 shared + phiếu theo dõi điều trị TM), bản giấy ký tay vẫn là gốc pháp lý. Pilot 2 chi nhánh (Cao Lãnh DL, Tân Bình II TM) trước khi mở rộng.
Quyết định còn mở
| PD | Câu hỏi | Lựa chọn / khuyến nghị | Phụ trách | Hạn chót | Trạng thái | Kết luận |
|---|---|---|---|---|---|---|
| PD-LEGAL-001 | Retention 10 năm: hot MinIO 1 năm + cold archive 9 năm — Legal/Infra duyệt? | A) Theo DEC-026 — khuyến nghị A | Legal + Infra | Trước pilot T-7 | Open | TBD |
| PD-LEGAL-002 | Sở Y tế chấp nhận luồng giấy ký tay + scan reference? | A) Có — go-live; B) Không — defer pilot | PO + Legal | Trước pilot T-7 | Open | TBD |
| PD-LEGAL-003 | Văn bản xác nhận mẫu giấy + retention + scan + trách nhiệm ký tay cho pilot? | A) Có văn bản → go-live; B) Chỉ xác nhận miệng → NO-GO | Legal + PO | Trước pilot T-7 | Open | TBD |
| PD-OPS-000 | D0 support owner, hotline, roster, scanner/printer/account test của CN pilot? | A) Đầy đủ → UAT; B) Còn TBD → NO-GO | Ops + QL CN | Trước UAT | Open | TBD |
| PD-OPS-001 | Cutoff/reminder mỗi CN pilot khác mặc định 20:00 không? | A) Trạng thái mặc định 20:00 Asia/Ho_Chi_Minh; B) Cấu hình riêng | Ops + QL CN | Trước UAT | Open | TBD — mặc định A |
| PD-DATA-001 | Import ICD-10 mới hơn bản 2015 trước pilot? | A) 2015 đủ; B) 2021 mới | Medical Lead + BE | Trước migration staging | Open | TBD — mặc định A |
Backlog giai đoạn 2 (ngoài phạm vi hiện tại)
| # | Tính năng | Lý do defer |
|---|---|---|
| 1 | Bệnh án điện tử đầy đủ TT46/2018 (chữ ký số, QR, liên thông Sở YT) | Scope pháp lý + kỹ thuật vượt Day-1 |
| 2 | Luồng xin quyền + đồng ý xem tầng 3 cross-branch trong app với SLA + consent số hoá | Cần legal sign-off riêng |
| 3 | Portal/mobile Phiếu khách tự khai từ xa với OTP + consent versioning | Tránh phụ thuộc auth/OTP/consent |
| 4 | Camera mobile + tag vùng cơ thể + so sánh timeline cho ảnh trước-sau | Phase 2 yêu cầu mobile work mạnh |
| 5 | Sales clinical recommendation engine | Tránh Sale suy diễn y khoa |
| 6 | Dropdown thuốc + cảnh báo tương tác | Pháp chế chưa cho kê trên PM |
| 7 | Report dịch tễ theo ICD-10 chapter | Phase 2 |
| 8 | Export bộ hồ sơ BA zip cho khi khách yêu cầu bản sao | Phase 2 |
Z) Nhật ký quyết định
44 DEC giữ 100% nội dung từ v1.5.10, refactor wording theo glossary canonical. Mọi FR phải tham chiếu đúng
DEC-xxx.
Z1) Quyết định nghiệp vụ
| ID | Quyết định | Lý do (≥2 phương án so sánh) | Ngày | Trạng thái |
|---|---|---|---|---|
| DEC-001 | Module Phòng khám bật/tắt theo CN. Trạng thái mặc định TẮT. CN spa thuần không thấy menu/module mới | A) Bật toàn hệ thống → confuse spa thuần; B) Per-tenant config → quá phức tạp; C) Per-branch flag → đã chọn: tránh ảnh hưởng CN không liên quan + triển khai an toàn | 21/04/2026 | Locked |
| DEC-002 | Tách clinical_profile (Hồ sơ bệnh án chính) và clinical_record (Bệnh án lượt khám). 1 lượt khám có DL+TM → 2 record khác form_type cho cùng appointment | A) 1 bảng gộp → lẫn mã hồ sơ KH với từng lượt; B) 2 bảng tách → đã chọn | 21/04/2026 | Locked |
| DEC-003 | Walk-in tạo appointment với order_item_id=NULL. Link muộn qua order.reference_appointment_id | A) Tạo order trước (giả) → luồng nghiệp vụ sai; B) Walk-in nullable → đã chọn: khớp luồng code hiện tại + appointment giữ semantic ổn định | 21/04/2026 | Locked |
| DEC-004 | BA Da liễu và Thẩm mỹ tách 2 khuôn biểu mẫu. 4 biểu mẫu shared (cam đoan, cam kết, đơn thuốc, dị ứng) dùng chung khuôn với placeholder {{branch.license_header}} | A) 1 form gộp → cấu trúc lẫn lộn; B) Tách 2 khuôn unique + 4 shared → đã chọn: khớp bản giấy hiện tại | 21/04/2026 | Locked |
| DEC-005 | Phiếu biểu mẫu lưu JSONB (clinical_form_instance.form_data) + form_template định nghĩa schema | A) Cột riêng cho từng field BA → BA TM 60+ field cứng nhắc; B) JSONB + JSON Schema → đã chọn: linh hoạt + GIN index query được | 21/04/2026 | Locked |
| DEC-006 | Dịch vụ active phải phân loại 3 status: mapped_requires_ba, explicitly_no_ba, unclassified. unclassified chặn phát hành | A) 2 trạng thái có/không → bỏ sót DV mới; B) 3 trạng thái → đã chọn: vận hành SaaS nhiều CN an toàn | 21/04/2026 | Locked |
| DEC-007 | Bản giấy in từ PM vẫn là gốc pháp lý sau khi BS+KH ký tay. PM lưu scan đối chiếu | A) E-signature số → cần legal sign-off + chứng thư số; B) Giấy ký tay + scan → đã chọn: phase 1 không dùng chữ ký số theo TT46/2018 | 21/04/2026 | Locked |
| DEC-028 | KH cũ trước bật module: không hồi cứu, chỉ BA mới | A) Hồi cứu toàn bộ → cost làm sạch khổng lồ; B) Không hồi cứu → đã chọn | 21/04/2026 | Locked |
| DEC-030 | Lifecycle module Phòng khám per CN: off → setup_draft → ready_to_publish → scheduled → live ↔ paused. Wizard hoàn tất chỉ đưa về ready_to_publish | A) 1 trạng thái on/off → mất review impact; B) 6 trạng thái có effective_at → đã chọn: tenant đang vận hành cần review + rollback path | 28/04/2026 | Locked |
Z2) Quyết định UX
| ID | Quyết định | Lý do (≥2 phương án so sánh) | Ngày | Trạng thái |
|---|---|---|---|---|
| DEC-019 | BA TM 4 phân hệ (Mắt/Mũi/Môi/Khác): auto-hiện section theo dịch vụ POS. BS có thể bật thêm section khác | A) Hiện full 4 section luôn → rối; B) Auto-hide theo dịch vụ → đã chọn: giảm click | 21/04/2026 | Locked |
| DEC-020 | Phiếu biểu mẫu tự lưu nháp 30 giây. BS thấy danh sách "Bản nháp" để quay lại | A) Lưu thủ công → mất data nếu BS quên; B) Autosave 30s → đã chọn | 21/04/2026 | Locked |
| DEC-021 | Giấy cam đoan: 2 checkbox đồng ý/không + KH tự gõ 1 câu xác nhận. Bản in KH vẫn viết tay | A) Chỉ checkbox → tính pháp lý yếu; B) Checkbox + tự gõ → đã chọn | 21/04/2026 | Locked |
| DEC-022 | Tải bản scan đã ký: cho phép từng tờ riêng hoặc 1 file PDF cả bộ. Trạng thái Đã ký + scan đủ chỉ khi checklist scan bắt buộc đủ theo case | A) 1 file = đủ → hiểu sai; B) Checklist theo case → đã chọn: bản scan đủ bộ mới có giá trị vận hành/pháp lý | 28/04/2026 | Locked |
| DEC-029 | UI surface Day-1: setup nằm ở Branch Detail tab thứ 4; Hồ sơ bệnh án là first-class tab thứ 17 của Customer Detail. CustomerInfo chỉ giữ summary card | A) Tạo màn cấu hình mới → trùng shell; B) Extend tab → đã chọn: khớp shell thật của repo | 27/04/2026 | Locked |
| DEC-032 | Sale có Trang xem an toàn (Sale): chỉ tầng 1+2 đã diễn giải an toàn, dùng dictionary safe_alert_*, CTA chuyển BS | A) Sale dùng full UI BS → leak tầng 3; B) Trang riêng + dictionary → đã chọn | 27/04/2026 | Locked |
| DEC-033 | BS có Bàn việc bác sĩ với 6 nhóm việc, task_key ổn định, queue_owner_*, CTA tiếp theo. need_record chỉ sinh khi appointment/order thật sự có dịch vụ mapped_requires_ba | A) BS đi từng tab rời → bỏ sót; B) Bàn việc gom 6 bucket → đã chọn: tránh false-positive task | 27/04/2026 | Locked |
| DEC-034 | KH có Phiếu khách tự khai dùng one-time token 15 phút. BS review/nhận mới ghi vào phiếu biểu mẫu BA với source audit | A) KH gửi tự do → tablet bị dùng sai KH/CN; B) Token + validate → đã chọn | 27/04/2026 | Locked |
Z3) Quyết định kỹ thuật
| ID | Quyết định | Lý do (≥2 phương án so sánh) | Ngày | Trạng thái |
|---|---|---|---|---|
| DEC-013 | Mã hồ sơ BA chính = DVA-[TM|DL]-[CN_CODE]-[YYYY]-[NNNNN], không reset theo năm | A) Reset năm → trùng mã giữa các năm; B) Monotonic → đã chọn | 21/04/2026 | Locked |
| DEC-014 | STT sổ khám bệnh = DVA-[CN_CODE]-[NNNNN]/[YYYY], reset năm | Quy chuẩn BYT | 21/04/2026 | Locked |
| DEC-015 | STT sổ thủ thuật = DVA-[CN_CODE]-TT-[NNNNN]/[YYYY], reset năm | Quy chuẩn BYT | 21/04/2026 | Locked |
| DEC-016 | ICD-10 = dropdown searchable, full ~22.000 mã. 1 primary required + 0–5 secondary optional. Diagnosis description = free text riêng | A) Free text → corruption report; B) Dropdown chuẩn → đã chọn | 21/04/2026 | Locked |
| DEC-017 | Bản ICD-10 2015 BYT làm mặc định; admin import bản mới | Bản 2015 phổ biến nhất | 21/04/2026 | Tinh giản cho ngày phát hành đầu |
| DEC-018 | Phiếu tiền sử dị ứng hardcode template TT51/2017, không cho admin edit. Chỉ cấu hình header CN | Mẫu pháp lý cố định | 21/04/2026 | Locked |
| DEC-037 | Clinical tables Day-1 ở source ecommerce. account thuộc default, lưu TEXT id + remote_relationship | A) Source default để FK account → migration không chạy được do FK cross-source; B) ecommerce + remote_relationship → đã chọn | 28/04/2026 | Locked |
| DEC-038 | Hasura action/event/scheduler dùng endpoint chung /actions /events /schedulers; dispatch theo name/table/payload bên trong | Khớp ecommerce-api vận hành; webhook không cấu hình /actions/foo nếu Gin không expose đường dẫn đó | 28/04/2026 | Locked |
| DEC-039 | Field-level medical writes phải đi qua action/service hoặc DB trigger/check. Raw mutation không bypass JSON schema, sensitivity tag, scan checklist, audit | JSONB linh hoạt nhưng dễ bypass nếu chỉ validate FE/action | 28/04/2026 | Locked |
| DEC-040 | Raw clinical tables không cấp select/insert/update trực tiếp cho vận hành role user. Runtime đọc qua action/secure view | A) Cấp raw → bypass DEC-008/009/010; B) Secure view/action → đã chọn | 28/04/2026 | Locked |
| DEC-041 | Runtime live gate = clinic_module_publication.status='live' AND effective_at<=now() cho CN. branch.features.clinic_enabled=true chỉ là setup flag | A) clinic_enabled đủ → bật vận hành nhầm; B) Publication gate → đã chọn | 28/04/2026 | Locked |
| DEC-042 | Rollback/downtime quay lại giấy: bản ghi reconcile dùng source_type='paper_fallback' + audit reason | A) Gộp manual → khó audit; B) Tách flag → đã chọn | 28/04/2026 | Locked |
Z4) Quyết định QA
| ID | Quyết định | Lý do | Ngày | Trạng thái |
|---|---|---|---|---|
| DEC-Q01 | 99 core test case + regression boundary D6 | Cover full functional + regression theo Impact Boundary Matrix | 28/04/2026 | Locked |
| DEC-Q02 | Test grant/revoke/portal split bắt buộc cho Permission v2 | Sale/y tá/QL CN có thể đổi quyền vận hành | 28/04/2026 | Locked |
| DEC-Q03 | Test boundary: allergy unknown chặn + high chặn + override luồng | An toàn y khoa | 28/04/2026 | Locked |
Z5) Quyết định an toàn
| ID | Quyết định | Lý do | Ngày | Trạng thái |
|---|---|---|---|---|
| DEC-008 | Phân 3 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) strict CN tạo, cross-branch chỉ theo policy Day-1 | Cân bằng an toàn KH + privacy + Nghị định 13/2023 | 21/04/2026 | Locked |
| DEC-009 | Sale tuyệt đối không xem tầng 3, kể cả cùng CN | Luật KCB 2023 điều 34 | 21/04/2026 | Locked |
| DEC-010 | Cross-branch tầng 3 Day-1: không build luồng xin quyền/đồng ý in-app. Quy trình ngoài hệ thống; chỉ Mở quyền khẩn cấp + audit mạnh | Giảm scope pháp lý cho pilot | 21/04/2026 | Locked |
| DEC-011 | Allergy safety = config-driven. allergy_risk_level có unknown/low/medium/high; unknown và high đều chặn | An toàn y khoa không 1-rule-fits-all | 21/04/2026 | Locked |
| DEC-012 | Dị ứng lần đầu BẮT BUỘC trước thủ thuật xâm lấn. Tái khám: BS tick "không đổi" hoặc điền mới | Tránh điền lại nhưng vẫn xác nhận chủ động | 21/04/2026 | Locked |
| DEC-023 | Lifecycle 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ữ. Không cho xóa BA y tế đã completed/printed/signed. Sửa sai sau in = in v2 | TT46/2018 yêu cầu không xoá BA | 21/04/2026 | Locked |
| DEC-024 | KH từ chối ký: ghi "Lý do không ký" + y tá ký làm chứng. Từ chối thủ thuật → hủy DV trong đơn + ghi sổ khám | Cover legal edge case | 21/04/2026 | Locked |
Z6) Quyết định phân quyền
| ID | Quyết định | Lý do | Ngày | Trạng thái |
|---|---|---|---|---|
| DEC-043 | Permission v2 là quy ước vận hành: effective_permission = role_module.actions + portal + branch_mode + backend enforcement. Tên vai trò chỉ là cấu hình mẫu ban đầu. Backend không tin view_mode từ FE và phải trả dữ liệu tối thiểu | A) Hard-code role → cứng nhắc + dễ lỗi; B) Dynamic + backend enforce → đã chọn | 28/04/2026 | Locked |
| DEC-044 | Impact Boundary Matrix là ranh giới scope chính thức. Module trực tiếp có owner/task/test; gián tiếp có guard; không ảnh hưởng phải có smoke regression | Feature L dễ scope creep | 28/04/2026 | Locked |
| DEC-025 | Go-live 3 giai đoạn: T1-2 song song giấy + PM; T3-4 PM chính + in ký; T5+ full PM + tải bản scan đã ký | Giảm rủi ro pháp lý | 21/04/2026 | Locked |
| DEC-026 | Lưu trữ 10 năm theo TT46/2018 (ngoại trú). Hot MinIO 1 năm + cold archive 9 năm | Giảm cost storage dài hạn | 21/04/2026 | Tinh giản cho ngày phát hành đầu |
| DEC-027 | Pilot 2 CN: Cao Lãnh (DL) + Tân Bình II (TM) | 2 loại PK khác nhau, đủ cover case | 21/04/2026 | Locked |
| DEC-031 | Kiểm tra sẵn sàng đạt 100% R-01..R-10 trước phát hành | Đảm bảo CN tự phục vụ cấu hình nhưng không gây lỗi pháp lý/vận hành | 27/04/2026 | Locked |
| DEC-035 | Ops có Trang điều phối phòng khám toàn chuỗi | Thấy rollout lệch trước khi thành lỗi | 27/04/2026 | Locked |
| DEC-036 | Mỗi CN đang hoạt động phải Chốt ngày phòng khám; cutoff theo cấu hình CN, mặc định 20:00 Asia/Ho_Chi_Minh | Pháp lý nằm ở hồ sơ in-ký-scan hoàn chỉnh | 27/04/2026 | Locked |
A) PRD
A0) Tổng quan tính năng
Đọc 2 phút nắm hết. Chi tiết xem A1-A8.
Ý tưởng cốt lõi: Số hóa hồ sơ bệnh án ngoại trú cho chuỗi spa/phòng khám Diva theo TT46/2018: tách clinical_profile (Hồ sơ bệnh án chính, mã DVA-[TM\|DL]-[CN]-[YYYY]-[NNNNN]) và clinical_record (Bệnh án lượt khám theo appointment + form_type); 7 biểu mẫu thực tế lưu JSONB linh hoạt; bản giấy ký tay vẫn là gốc pháp lý + scan đối chiếu; phân quyền 3 tầng (an toàn / kinh doanh / y tế nhạy) qua Permission v2; pilot 2 CN trước khi mở rộng.
Kiến trúc tổng thể:
┌─────────────────────────────────────────────────────────────────────┐
│ Branch Detail (tab Phòng khám) — 5 bước cấu hình per CN │
│ 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 │
│ ↓ (Kiểm tra sẵn sàng đạt 100% R-01..R-10) │
│ clinic_module_publication: off → setup_draft → ready_to_publish │
│ → scheduled → live ↔ paused │
└──────────────────────────────────┬──────────────────────────────────┘
↓ (CN đang hoạt động)
┌─────────────────────────────────────────────────────────────────────┐
│ Customer Detail (CRM) — tab thứ 17 "Hồ sơ bệnh án" │
│ ├─ Hồ sơ bệnh án chính (clinical_profile, mã DVA-...) │
│ └─ Bệnh án lượt khám (clinical_record, theo appointment+form_type) │
│ ├─ Phiếu biểu mẫu (7 loại: BA DL/TM, cam đoan, ...) │
│ ├─ Đơn thuốc (prescription) │
│ ├─ Phiếu theo dõi điều trị (TM only) │
│ └─ File: bản scan đã ký, ảnh trước-sau điều trị │
└──────────────────────────────────┬──────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────────┐
│ Vận hành hằng ngày │
│ ├─ Bàn việc bác sĩ — 6 nhóm việc trong ngày │
│ ├─ Phiếu khách tự khai — token 15 phút │
│ ├─ Trang xem an toàn (Sale) — chỉ tầng 1+2 │
│ ├─ Phiếu chuyển bác sĩ tư vấn (Sale → BS) │
│ ├─ Trang điều phối phòng khám — Ops toàn chuỗi │
│ └─ Chốt ngày phòng khám — cutoff 20:00 hoặc theo CN │
└─────────────────────────────────────────────────────────────────────┘Mapping FR ↔ SCR ↔ Dev:
| Khối | FR | SCR | Dev section |
|---|---|---|---|
| Module bật/tắt | FR-001 | SCR-04 | C4.1, C4.3 |
| Cấu hình 5 bước | FR-002 | SCR-04a..e | C4.2, C4.4, C4.5 |
| Phân loại dịch vụ — kỹ thuật | FR-003 | SCR-04d | C4.5 |
| Tạo lượt khám + walk-in | FR-004 | SCR-05 | C2 (refactor), C4 appointment |
| BA Da liễu | FR-005 | SCR-06 | C4.6, C4.7, C4.8, C4.9 |
| BA Thẩm mỹ | FR-006 | SCR-07 | C4.6..C4.10 |
| 5 biểu mẫu shared | FR-007 | SCR-08 | C4.6, C4.9, C4.11 |
| Tự lưu nháp | FR-008 | SCR-06, SCR-07 | C5 action autosaveClinicalForm |
| In + scan ký | FR-009 | SCR-09, SCR-10 | C5 action printClinicalRecord + uploadClinicalScan |
| An toàn dị ứng | FR-010 | (cross-màn hình) | C4.13, C4.14 |
| Permission 3 tầng | FR-011 | (cross-màn hình) | C4.15, C8 |
| Sổ khám + sổ thủ thuật | FR-012 | SCR-11, SCR-12 | C5 query, C9 export |
| Notification | FR-013 | (cross) | C5 events |
| Sequence generator | FR-014 | (cross) | C5 action generateSequence |
| Kiểm tra sẵn sàng + phát hành | FR-015 | SCR-04f | C4.3 |
| Trang xem an toàn (Sale) | FR-016 | SCR-13 | C4.16 |
| Bàn việc bác sĩ | FR-017 | SCR-14 | C5 query doctor_workbench_view |
| Phiếu khách tự khai | FR-018 | SCR-15 | C4.17, C5 token |
| Trang điều phối + Chốt ngày | FR-019 | SCR-16, SCR-17 | C4.18, C5 cron |
Quyết định chính theo chủ đề:
| Nhóm | Tóm tắt | Tham chiếu |
|---|---|---|
| Kiến trúc | Tách clinical_profile ↔ clinical_record; JSONB form data; source ecommerce; remote_relationship cho account; Permission v2 là quy ước vận hành | DEC-002, DEC-005, DEC-037, DEC-040, DEC-041, DEC-043 |
| Nghiệp vụ | Walk-in nullable; classification 3 trạng thái; bản giấy ký tay là gốc; 3 tầng dữ liệu; allergy unknown+high chặn | DEC-001..DEC-012, DEC-022 |
| UX | BA TM auto-hide; autosave 30s; Bàn việc bác sĩ 6 nhóm việc; Phiếu khách tự khai token; Trang xem an toàn (Sale) | DEC-019..DEC-022, DEC-029, DEC-032..DEC-034 |
| Vận hành | Lifecycle 6 trạng thái module; pilot 2 CN; go-live 3 giai đoạn; Chốt ngày 20:00 mặc định; Impact Boundary Matrix | DEC-025..DEC-027, DEC-030, DEC-031, DEC-035, DEC-036, DEC-044 |
Bảng FR tóm tắt:
| FR | Mô tả (1 dòng) | Ưu tiên | Giai đoạn |
|---|---|---|---|
| FR-001 | Bật/tắt module Phòng khám per CN, mặc định tắt | Must | 1 |
| FR-002 | Cấu hình 5 bước khi bật Phòng khám | Must | 1 |
| FR-003 | Phân loại dịch vụ — kỹ thuật 3 trạng thái per CN | Must | 1 |
| FR-004 | Tạo lượt khám với walk-in support | Must | 1 |
| FR-005 | Điền BA Da liễu | Must | 1 |
| FR-006 | Điền BA Thẩm mỹ với 4 phân hệ structured | Must | 1 |
| FR-007 | Điền 5 biểu mẫu shared | Must | 1 |
| FR-008 | Tự lưu nháp 30 giây | Must | 1 |
| FR-009 | In bộ hồ sơ + tải bản scan đã ký | Must | 1 |
| FR-010 | Kiểm tra an toàn dị ứng | Must | 1 |
| FR-011 | Permission 3 tầng + audit cross-branch tầng 3 | Must | 1 |
| FR-012 | Sổ khám bệnh + sổ thủ thuật | Must | 1 |
| FR-013 | Notification "cần BA" + "BA thiếu" | Must | 1 |
| FR-014 | Sequence generator generic | Must | 1 |
| FR-015 | Kiểm tra sẵn sàng + an toàn phát hành per CN | Must | 1 |
| FR-016 | Trang xem an toàn (Sale) + Phiếu chuyển bác sĩ tư vấn | Must | 1 |
| FR-017 | Bàn việc bác sĩ với 6 nhóm việc | Must | 1 |
| FR-018 | Phiếu khách tự khai (token 15 phút) | Should | 1 |
| FR-019 | Trang điều phối phòng khám + Chốt ngày phòng khám | Must | 1 |
Mô hình dữ liệu tóm tắt:
| Bảng | Loại | Mục đích |
|---|---|---|
branch.features JSONB | SỬA (ALTER) | Feature flag per CN |
appointment.OrderItemID Go struct | SỬA (refactor *uuid.UUID) | Walk-in support |
clinical_profile | MỚI | Hồ sơ bệnh án chính per KH/CN/loại PK |
clinical_record | MỚI | Bệnh án lượt khám theo appointment+form_type |
clinical_form_instance | MỚI | 1 phiếu biểu mẫu (JSONB form_data) |
form_template | MỚI | Khuôn biểu mẫu (JSON Schema) |
technical_category | MỚI | Danh mục kỹ thuật per CN |
service_clinical_classification | MỚI | Phân loại dịch vụ — kỹ thuật per CN |
branch_technical_config | MỚI | Cấu hình clinical per CN (cutoff, ...) |
clinic_module_publication | MỚI | Bản phát hành phòng khám per CN |
prescription + prescription_item | MỚI | Đơn thuốc structured |
treatment_progress_entry | MỚI | Phiếu theo dõi điều trị (TM only) |
icd10_code | MỚI + SEED | Catalog ICD-10 ~22.000 mã |
allergy_check_policy | MỚI | Rule allergy theo KT |
allergy_check_skip_log | MỚI | Log skip allergy check |
medical_record_access_log | MỚI | Audit truy cập tầng 3 |
clinical_sales_handoff | MỚI | Phiếu chuyển bác sĩ tư vấn |
customer_clinical_intake | MỚI | Phiếu khách tự khai (token 15ph) |
clinic_daily_close | MỚI | Chốt ngày phòng khám per CN/date |
sequence_generator | MỚI | Generic sequence per entity_type+branch_id+year |
Ảnh hưởng code hiện tại: xem dev-spec.md C2 chi tiết. High-risk: pkg/store/appointment.go:52 (refactor), 5 call site null-guard (appointment_update.go:191, appointment_insert.go:81/176/202, ticket.go:526).
A1) Bản thiết kế tóm tắt
| Trường | Giá trị |
|---|---|
| Tính năng | Hồ sơ bệnh án (Da liễu + Phẫu thuật Thẩm mỹ) |
| Loại | Tính năng mới |
| Nền tảng | Web Admin (diva-admin — User/CRM/Settings/Ecommerce/POS modules) |
| Module ảnh hưởng | FE: crm, user, ecommerce, settings, clinical (mới); BE: ecommerce-api (chính), auth, notification-v2-api |
| Database | Source ecommerce (18 bảng mới); Source default (Permission v2 extend: 8 module + 22 action mới) |
A2) Bối cảnh
Hiện trạng (As-Is):
- Phòng khám Diva (DL + TM) điền BA bằng giấy tay theo mẫu BYT
- Khi thanh tra Sở YT: nhân viên phải lục thư mục giấy theo CN; bản giấy mất / ố mực / ghi sai khó tra cứu
- BS chi nhánh khác không nắm tiền sử dịch vụ + dị ứng KH; Sale không có nguồn dữ liệu y tế tóm tắt khi tư vấn
- KH phải khai lại tiền sử mỗi lần đến; BS phải tự nhớ "hôm nay còn BA nào chưa hoàn thành"
- Ops không có cách thấy CN nào triển khai phòng khám đang lệch cấu hình
- Đơn thuốc viết tay khó truy vết; xem tầng 3 khác CN chưa có cơ chế audit
Kỳ vọng (To-Be):
- Bệnh án digital theo TT46/2018, TT51/2017, TT52/2017; bản giấy ký tay vẫn là gốc pháp lý + scan đối chiếu
- 7 biểu mẫu thực tế: 2 unique (BA DL, BA TM 4 phân hệ) + 4 shared (cam đoan, cam kết, đơn thuốc, dị ứng) + 1 TM-only (phiếu theo dõi điều trị)
- Phân quyền 3 tầng theo Permission v2; Sale chặn cứng tầng 3; cross-branch tầng 3 chỉ qua Mở quyền khẩn cấp + audit
- Bàn việc bác sĩ 6 nhóm việc trong ngày; Phiếu khách tự khai trước khám; Trang xem an toàn cho Sale; Trang điều phối Ops; Chốt ngày phòng khám
- Pilot 2 CN: Cao Lãnh (DL) + Tân Bình II (TM)
Tại sao làm bây giờ:
- Compliance: Sở YT có thể thanh tra bất kỳ lúc nào; phạt hành chính nếu tra cứu chậm
- An toàn: dị ứng cross-CN không được cảnh báo → rủi ro y khoa
- Mở rộng chuỗi: muốn mở thêm CN có giấy phép phòng khám nhưng không có công cụ kiểm soát rollout
Ràng buộc:
- Pháp lý: TT46/2018 cấm xóa BA; TT51/2017 cố định mẫu phiếu dị ứng; Luật KCB 2023 điều 34 hạn chế Sale xem y tế; Nghị định 13/2023 BVDL cá nhân
- Kỹ thuật: Hasura vận hành role
userkhông được expose raw clinical (DEC-040); cross-source FK qua remote_relationship; PDF generation external
Đồng thuận stakeholder:
- PO/BA: Sơn Thọ — chốt phạm vi + DEC
- Tech Lead: TBD — sign-off architecture, refactor
Appointment.OrderItemID - QA Lead: TBD — sign-off test coverage 99 core TC + regression boundary
- Medical Lead: TBD — sign-off allergy_risk_level cho danh mục KT
- Legal: TBD — sign-off retention 10 năm + luồng giấy ký tay
- Ops: TBD — sign-off pilot setup CN
Không thuộc phạm vi (Non-goals):
| # | Mục | Lý do |
|---|---|---|
| 1 | Bệnh án điện tử đầy đủ TT46/2018 (chữ ký số, QR, liên thông Sở YT) | Scope pháp lý + kỹ thuật vượt Day-1 |
| 2 | Bộ hồ sơ đầy đủ cho khách chỉ khám không làm dịch vụ | Day-1 chỉ ghi visit-only log nếu CN cần |
| 3 | Hồi cứu BA giấy cũ trước khi bật module | Cost làm sạch khổng lồ |
| 4 | Luồng xin quyền + đồng ý tầng 3 cross-branch trong app với SLA + consent số hoá | Cần legal sign-off riêng — Phase 2 |
| 5 | Portal/mobile cho KH tự khai từ xa ngoài CN | Phase 1 dùng tablet/quầy nội bộ |
| 6 | Sale xem chẩn đoán/form BA/scan/ảnh y tế tầng 3 | Quy định cứng — không override qua Permission v2 |
| 7 | Tự động chẩn đoán AI / suggest điều trị | Không scope |
| 8 | Telemedicine (khám từ xa video) | Không scope |
| 9 | Xuất BA theo format BHYT thanh toán | Không scope |
A3) Mục tiêu, persona và chỉ số thành công
Mục tiêu:
| Mục tiêu | Cách đo | Mục tiêu đo |
|---|---|---|
| Compliance pháp lý TT46/2018 | Audit Sở YT đạt | 100% pilot (2 CN) |
| An toàn KH (cảnh báo dị ứng cross-CN) | Tỷ lệ thủ thuật xâm lấn không bị chặn do unknown allergy | < 5% sau pilot 30 ngày |
| Tỷ lệ BA hoàn thành đúng ngày | FORMULA-004 | ≥ 90% sau pilot 30 ngày |
| Thời gian BS điền 1 BA (TB) | FORMULA-005 | ≤ 8 phút BA DL; ≤ 12 phút BA TM |
| Tỷ lệ BA đủ chữ ký + scan đủ | FORMULA-006 | ≥ 95% sau pilot 30 ngày |
| Thời gian Ops thấy drift cấu hình | Trang điều phối phòng khám | < 1 giờ |
Persona:
| Persona | Vai trò | JTBD | Tần suất |
|---|---|---|---|
| Bác sĩ Da liễu | BS DL | Khám và điền BA DL, kê đơn, theo dõi liệu trình DL | Mỗi lượt khám DL |
| Bác sĩ Thẩm mỹ | BS TM | Khám, tư vấn TM, điền BA TM 4 phân hệ, theo dõi tiến trình điều trị | Mỗi lượt khám TM |
| Y tá hỗ trợ | NS | Hỗ trợ phần hành chính, scan ký, làm chứng | Mỗi lượt khám |
| Lễ tân | RCP | Tạo đơn POS, mở phiên khách tự khai, đẩy thông báo "cần BA" | Mỗi lượt KH đến |
| Tư vấn viên (Sale) | SLS | Tư vấn dịch vụ phù hợp tình trạng KH (qua Trang xem an toàn) | Mỗi lượt tư vấn |
| Quản lý chi nhánh | BM | Duyệt sổ khám/thủ thuật, giám sát BA chưa hoàn thành, chốt ngày | Hằng ngày |
| Admin/Ops | ADM/OPS | Bật/tắt module, cấu hình 5 bước, theo dõi rollout toàn chuỗi | Tuần |
| Khách hàng | CUS | Tự khai phiếu trước khám tại quầy/tablet | Lần đầu / khi có thay đổi |
A4) Yêu cầu chức năng
Mọi FR phải trả lời đủ 6 yếu tố (vai trò + dữ liệu + điều kiện + hành động + kết quả + ngoại lệ) và tham chiếu DEC.
FR-001 — Bật/tắt module Phòng khám per CN
Tham chiếu: DEC-001, DEC-030, DEC-041 | Ưu tiên: Must | SCR: SCR-04
Mô tả nghiệp vụ phần mềm:
- Vai trò: Admin/Ops; QL CN xem CN mình
- Dữ liệu:
branch.features.clinic_enabled,clinic_module_publication.status/effective_at - Điều kiện: Branch type = clinic-eligible (có giấy phép phòng khám) hoặc Admin force mở
- Hành động: Vào Branch Detail → tab Phòng khám (chỉ hiện nếu có quyền
clinic_module.access); bật toggle "Bật module Phòng khám"; chuyển trạng thái sangsetup_draft - Kết quả:
branch.features.clinic_enabled=true;clinic_module_publicationcó row mớistatus='setup_draft'; CN spa thuần mặc địnhfalse, tab Phòng khám không hiện - Ngoại lệ: Không có quyền
configure→ ẩn toggle; CN đãlivemuốn pause → cần quyềnphát hành+ lý do; rollback:paused, không xóa publication
AC:
- [ ] Khi Admin bật module ở CN Cao Lãnh chưa từng có publication → tạo
clinic_module_publicationvớistatus='setup_draft',branch.features.clinic_enabled=true - [ ] Khi role
staff(Lễ tân) vào Branch Detail CN Cao Lãnh → tab Phòng khám không hiện (không cóclinic_module.access) - [ ] Khi CN đang
livechuyển sangpaused→ menu/UI clinical hiện banner "Module đã tạm dừng từ{DD/MM/YYYY HH:mm}"; không tạo BA mới được - [ ] Khi rollback từ
livevềpaused→ BA cũ vẫn xem được (read-only); croncronClinicalDailyCloseskip CN này
FR-002 — Cấu hình 5 bước khi bật Phòng khám
Tham chiếu: DEC-002, DEC-004, DEC-029, DEC-031 | Ưu tiên: Must | SCR: SCR-04a..SCR-04e
Mô tả nghiệp vụ phần mềm:
- Vai trò: Admin/Ops cấu hình; QL CN xem readonly
- Dữ liệu:
branch_technical_config(loại PK, license_header, cutoff),technical_category(danh mục KT),service_clinical_classification(phân loại dịch vụ — kỹ thuật), Permission v2 seed - Điều kiện: Module ở
setup_drafthoặcpaused - Hành động: Wizard 5 bước theo thứ tự: (1) Loại phòng khám DL/TM/cả hai · (2) Giấy phép Sở YT (upload file scan + license_number + expiry) · (3) Danh mục kỹ thuật (chọn từ master + tự thêm) · (4) Phân loại dịch vụ — kỹ thuật (mỗi DV active phải có 1 trong 3 trạng thái) · (5) Phân quyền nhân sự (gán role + module) · Bước 6 (gate): Kiểm tra sẵn sàng (R-01..R-10)
- Kết quả: Wizard hoàn tất =
status='ready_to_publish'; chưa tựlive - Ngoại lệ: Bước 4 còn
unclassified→ chặn sang bước 5; bước 6 không đạt R-xx → highlight mục lỗi + deeplink sang màn cần sửa + nút "Quay lại Phòng khám"
AC:
- [ ] Khi Admin chọn loại "Cả DL+TM" → bước 3 hiện cả 2 nhóm KT; bước 4 cho phép phân loại theo DL hoặc TM
- [ ] Khi bước 4 còn 5 dịch vụ
unclassified→ bước 5 bị khóa; banner "Còn 5 dịch vụ chưa phân loại → Đến danh mục dịch vụ" - [ ] Khi bước 6 R-03 (giấy phép) hết hạn → highlight đỏ + deeplink sang bước 2; không cho phát hành
- [ ] Khi hoàn tất 6 bước + tất cả R-xx đạt → CTA "Phát hành" hiện; chuyển sang
ready_to_publish
FR-003 — Phân loại dịch vụ — kỹ thuật 3 trạng thái
Tham chiếu: DEC-006, DEC-031 | Ưu tiên: Must | SCR: SCR-04d
Mô tả nghiệp vụ phần mềm:
- Vai trò: Admin/Ops cấu hình per CN
- Dữ liệu:
service_clinical_classification(branch_id, product_id, classification_status, technical_category_id) - Điều kiện: CN đã chọn loại PK ở bước 1; có dịch vụ active
- Hành động: Hiển thị bảng dịch vụ active theo CN với cột "Phân loại"; mỗi dòng cho phép chọn 1 trong 3: (a)
mapped_requires_ba(cần BA — phải chọn KT); (b)explicitly_no_ba(xác nhận không cần BA); (c)unclassified(chưa phân loại — mặc định cho DV mới) - Kết quả: Lưu phân loại; nếu
mapped_requires_bathì link vớitechnical_category_id - Ngoại lệ: Còn
unclassified→ chặn phát hành; sau khilive, dịch vụ mới active mặc địnhunclassified→ cảnh báo Ops "Lệch cấu hình: 3 dịch vụ chưa phân loại tại CN Cao Lãnh"
AC:
- [ ] Khi Admin có 50 dịch vụ active tại CN → table hiển thị 50 dòng; mặc định tất cả
unclassified - [ ] Khi Admin chọn
mapped_requires_bacho dịch vụ "Liệu trình trị mụn" + KT "Áp lạnh nitơ" → lưu thành công - [ ] Khi Admin để 5 dịch vụ
unclassifiedvà bấm "Tiếp" → chặn + banner "Còn 5 dịch vụ chưa phân loại" - [ ] Sau khi CN
live, Admin thêm dịch vụ "Filler Hyaluronic" → mặc địnhunclassified+ Trang điều phối hiển thị cảnh báo "Lệch cấu hình"
FR-004 — Tạo lượt khám với walk-in support
Tham chiếu: DEC-003 | Ưu tiên: Must | SCR: SCR-05 | CRITICAL: Walk-in safety
Mô tả nghiệp vụ phần mềm:
- Vai trò: Lễ tân, BS, Y tá tạo; Khách hàng có thể tham gia qua Phiếu khách tự khai
- Dữ liệu:
appointment.order_item_id(NULL được),order.reference_appointment_id,Appointment.OrderItemID *uuid.UUID(Go struct) - Điều kiện: CN ở
live; KH đã có hoặc tạo mới (walk-in) hoặc chưa có - Hành động: Hai đường: (a) Tạo từ lịch hẹn có sẵn →
order_item_idđã có; (b) Walk-in: tạoappointmentvớicustomer_id=NULLhoặc tạo KH mới +order_item_id=NULL; sau khám tạo đơn → đơn córeference_appointment_idlink muộn, không backfillappointment.order_item_id - Kết quả:
appointmentrow mới; nếu walk-in →order_item_id IS NULL; sau khám tạoorder→order.reference_appointment_idlink - Ngoại lệ: Code Go cũ chưa null-guard
appointment.OrderItemID→ cần refactor*uuid.UUID+ null-guard 5 call site (Phase 0 blocker); CN spa thuần (features.clinic_enabled=false) → walk-in vẫn tạo được nhưng không gắn clinical record
AC:
- [ ] Lễ tân tạo walk-in cho khách Nguyễn Thị Lan tại CN Tân Bình II 14:30 ngày 02/05/2026 →
appointmentinsert vớicustomer_id={Nguyễn Thị Lan},order_item_id=NULL,branch_id={Tân Bình II} - [ ] Sau khám 30 phút BS bấm "Tạo đơn" →
orderinsert vớireference_appointment_id={appointment.id};appointment.order_item_idvẫn NULL - [ ] Khi
appointment_update.go:191query vớiorder_item_id IS NULL→ null-guardif appointment.OrderItemID != niltrước khi build query (test: walk-in không crash event handler) - [ ] Khi gọi từ Bàn việc bác sĩ với appointment walk-in →
need_recordtask hiện đầy đủ (task_key=ba_DLM_2026_001,queue_owner_type=doctor,queue_owner_id={BS})
FR-005 — Điền BA Da liễu
Tham chiếu: DEC-004, DEC-005, DEC-016, DEC-020, DEC-023 | Ưu tiên: Must | SCR: SCR-06
Mô tả nghiệp vụ phần mềm:
- Vai trò: Bác sĩ Da liễu cùng CN
- Dữ liệu:
clinical_record.form_type='DL',clinical_form_instance.form_template_id={form_template.DL},form_dataJSONB; ICD-10 code viaicd10_code - Điều kiện: Có
clinical_recordở trạng tháiBản nháphoặcĐã hoàn thành; BS có quyềnclinical_record.edit_medical_form - Hành động: Mở form BA DL với section expandable (Hành chính → Tiền sử → Khám hiện tại → Chẩn đoán → Y lệnh → Theo dõi); BS điền theo từng section; chẩn đoán dùng dropdown ICD-10 searchable (1 primary required + 0-5 secondary optional); diagnosis description = free text riêng; tự lưu nháp 30s (FR-008); BS bấm "Hoàn thành" để chuyển trạng thái
- Kết quả:
clinical_record.status='Đã hoàn thành';clinical_form_instance.form_datalưu đầy đủ JSON;completed_at=NOW() - Ngoại lệ: Allergy
unknowncho KT thủ thuật → chặn "Hoàn thành" (FR-010); thiếu primary ICD-10 → validation lỗi inline; BS không cùng CN → 401 (Permission v2 enforcement); KH từ chối ký → luồng DEC-024
AC:
- [ ] BS DL CN Cao Lãnh mở BA cho khách Lê Thị Hương → form hiện 6 section, mặc định các field rỗng
- [ ] BS chọn ICD-10 primary
L70.0(mụn trứng cá thông thường) + secondaryL73.2→ cả 2 lưu vàoform_data.diagnosis_codes - [ ] BS bấm "Hoàn thành" mà chưa chọn primary ICD → validation lỗi inline focus vào field "Chẩn đoán chính"
- [ ] BS không cùng CN cố mở BA → API trả 401, FE hiện "Bạn không có quyền xem nội dung này"
FR-006 — Điền BA Thẩm mỹ với 4 phân hệ structured
Tham chiếu: DEC-004, DEC-005, DEC-019, DEC-023 | Ưu tiên: Must | SCR: SCR-07
Mô tả nghiệp vụ phần mềm:
- Vai trò: Bác sĩ Thẩm mỹ cùng CN
- Dữ liệu:
clinical_record.form_type='TM';clinical_form_instance.form_template_id={form_template.TM}; 4 phân hệ Mắt/Mũi/Môi/Khác - Điều kiện: Có
clinical_recordform_type=TM - Hành động: Form auto-hiện section theo dịch vụ POS đã chọn (DEC-019); BS có thể bật thêm phân hệ; mỗi phân hệ có 60+ field structured (đo đạc Mắt: hẹp mí trên/dưới, sa trễ; đo Mũi: chiều cao sống, độ rộng cánh; đo Môi: tỷ lệ trên/dưới); chẩn đoán + y lệnh chi tiết
- Kết quả:
clinical_form_instance.form_dataJSON; lifecycle như BA DL - Ngoại lệ: BS muốn bật thêm phân hệ "Khác" mà không có dịch vụ → cho phép + cảnh báo "Phân hệ này không được chọn từ dịch vụ POS"
AC:
- [ ] Khách mua liệu trình "Nâng mũi cấu trúc" → form TM auto-hiện section "Mũi" (đầy đủ 60+ field), ẩn section Mắt/Môi
- [ ] BS bật thêm section "Khác" để ghi chú → form hiện section thứ 2 + banner "Phân hệ này không được chọn từ dịch vụ POS"
- [ ] Lưu nháp với 30 field đã điền + 30 field còn rỗng → autosave 30s OK
- [ ] BS bấm "Hoàn thành" mà thiếu primary ICD-10 → validation lỗi
FR-007 — Điền 5 biểu mẫu shared (kèm rule câu xác nhận tự gõ + luồng từ chối thủ thuật)
Tham chiếu: DEC-004, DEC-018, DEC-021, DEC-024 | Ưu tiên: Must | SCR: SCR-08
Mô tả nghiệp vụ phần mềm:
- Vai trò: BS điền nội dung; KH ký + tự gõ xác nhận; Y tá hỗ trợ + làm chứng
- Dữ liệu: 5 biểu mẫu shared: cam đoan, cam kết, đơn thuốc, phiếu tiền sử dị ứng, phiếu theo dõi điều trị (TM only);
clinical_record.customer_refused_procedure/refusal_reason/witness_nurse_id/cancelled_order_item_idcho luồng từ chối thủ thuật - Điều kiện:
clinical_recordởBản nháphoặcĐã hoàn thành - Hành động:
- Mỗi biểu mẫu là
clinical_form_instanceriêng vớiform_template_idtương ứng; cam đoan có placeholder{{branch.license_header}}(khác giữa các CN); phiếu tiền sử dị ứng dùng template hardcode TT51/2017, không cho admin edit. - DEC-021 — Câu xác nhận tự gõ: trong giấy cam đoan, KH tự gõ 1 câu xác nhận theo rule cứng: ≥ 20 ký tự (sau trim), phải chứa "đồng ý" hoặc "thực hiện" (không phân biệt hoa thường), FE chặn
paste/copy-paste, FE log nhịp gõ + server lưutyped_atvàtyped_duration_msđể audit nghi vấn auto-typer (>30 ký tự/giây flagsuspicious_typing=true). - DEC-024 — Khách từ chối thủ thuật: trong cam đoan có nút "Khách từ chối thủ thuật" → mở hộp thoại bắt nhập
refusal_reason≥ 30 ký tự + chọnwitness_nurse_id(y tá cùng CN); xác nhận → hệ thống huỷorder_itemcủa thủ thuật, đánh dấuclinical_record.customer_refused_procedure=true+refusal_type='procedure', ghi sổ khám "Kết quả: Khách từ chối thủ thuật", giữ Bệnh án DL nếu cùng appointment đã có (không touch), KHÔNG tạo Bệnh án thủ thuật mới, gửinoti_clinical_procedure_refusedcho QL CN + Sale phụ trách.
- Mỗi biểu mẫu là
- Kết quả: Mỗi biểu mẫu = 1
clinical_form_instance; gắn vàoclinical_recordcùngappointment + form_type. Khi từ chối thủ thuật:order_item.status='cancelled'vớicancel_reason='customer_refused_procedure', auditmedical_record_access_log action='refuse_procedure'. - Ngoại lệ:
- KH không tự gõ câu xác nhận hợp lệ → chặn "Hoàn thành" cam đoan
- Admin cố edit phiếu dị ứng template → API trả 403
- User thiếu quyền
clinical_record.refuse_procedure→ CTA "Khách từ chối thủ thuật" ẩn; gọi action trực tiếp → 403 - User thiếu quyền
order.update→ CTA hiện nhưng action trả 422 "Bạn không có quyền huỷ đơn dịch vụ. Liên hệ QL CN." - Re-call action trên record đã từ chối → 409 idempotency
AC:
- [ ] AC-007.1 BS bấm "Tạo đơn thuốc" trong BA → mở phiếu đơn thuốc với 5 dòng thuốc mặc định; điền tên thuốc + liều + cách dùng + số ngày
- [ ] AC-007.2 BS in giấy cam đoan tại CN Cao Lãnh → header có "Phòng khám Da liễu Diva Cao Lãnh — Giấy phép số {license_number}"
- [ ] AC-007.3 Admin cố sửa template phiếu dị ứng → API trả 403; UI hiện "Phiếu tiền sử dị ứng tuân theo TT51/2017, không thể sửa"
- [ ] AC-007.4.1 (DEC-021) KH gõ câu xác nhận <20 ký tự → FE inline lỗi
error.confirmation_too_short; nút "Lưu phiếu" khoá; server bypass FE cũng reject 422 - [ ] AC-007.4.2 (DEC-021) Câu xác nhận đủ 20 ký tự nhưng thiếu cả "đồng ý" và "thực hiện" → cùng lỗi; thêm "đồng ý" → unblock
- [ ] AC-007.4.3 (DEC-021) KH cố dán nội dung từ clipboard → FE chặn
pasteevent + thông báo nhanherror.confirmation_paste_blocked; câu vẫn rỗng - [ ] AC-007.4.4 (DEC-021) Tốc độ gõ >30 ký tự/giây (gợi ý macro) → server log
suspicious_typing=true+ flag để compliance review; KHÔNG block submission để tránh chặn nhầm KH gõ nhanh thật - [ ] AC-007.5 Đơn thuốc có ít nhất 1 thuốc → server enforce required liều/cách dùng + save structured
- [ ] AC-007.6 Phiếu theo dõi điều trị: thêm entry mới không sửa entry cũ; entry cũ readonly + audit timestamp
- [ ] AC-007.7.1 (DEC-024) BS bấm "Khách từ chối thủ thuật" → hộp thoại; nhập lý do ≥30 ký tự + chọn y tá làm chứng → xác nhận →
clinical_record.customer_refused_procedure=true,cancelled_order_item_idlưu,order_item.status='cancelled'vớicancel_reason='customer_refused_procedure', sổ khám hiện cột "Kết quả: Khách từ chối thủ thuật",medical_record_access_logghi actionrefuse_procedure, NTF-14 gửi QL CN + Sale phụ trách - [ ] AC-007.7.2 (DEC-024) Hộp thoại không cho xác nhận khi
witness_nurse_idrỗng → copyerror.refusal_witness_required; bypass FE → server reject 422 - [ ] AC-007.7.3 (DEC-024) Khách từ chối thủ thuật khi đã có Bệnh án DL
completed/signedcùng appointment → BA DL không bị thay đổi; chỉ huỷorder_itemthủ thuật;preserved_dl_record_idtrả về cho FE confirm - [ ] AC-007.7.4 (DEC-024 + Permission v2) User thiếu
clinical_record.refuse_procedure→ CTA ẩn ở SCR-08, gọi action trực tiếp → 403; thiếuorder.update→ CTA hiện nhưng action → 422 với copy hướng dẫn liên hệ QL CN - [ ] AC-007.7.5 (DEC-024)
clinical_record.status='printed'/'signed'đã in/ký → actionrefuse_clinical_procedurereject 422 "Bệnh án đã in/ký, không thể ghi nhận từ chối thủ thuật. Sửa qua bản v2 (DEC-023)."
FR-008 — Tự lưu nháp 30 giây
Tham chiếu: DEC-020 | Ưu tiên: Must | SCR: SCR-06, SCR-07, SCR-08
Mô tả nghiệp vụ phần mềm:
- Vai trò: Hệ thống (FE auto trigger); BS xem
- Dữ liệu:
clinical_form_instance.form_data(JSONB) - Điều kiện: Form đang ở
Bản nháp; có thay đổi chưa lưu - Hành động: FE debounce 30 giây sau khi BS dừng gõ → POST mutation
update_clinical_form_instancevớiform_datamới; show "Đã lưu nháp lúc HH:mm" cuối form - Kết quả:
form_datacập nhật;updated_at=NOW() - Ngoại lệ: Mất mạng → thông báo nhanh "Mất kết nối. Đã lưu local. Đang thử lại..."; 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"
AC:
- [ ] BS gõ 30 field → 30 giây sau dừng gõ → backend nhận mutation, response 200, FE hiện "Đã lưu nháp lúc 14:32"
- [ ] BS gõ liên tục 5 phút → debounce reset mỗi lần gõ → chỉ lưu 1 lần sau khi dừng 30s
- [ ] Mất mạng giữa lúc autosave → thông báo nhanh "Mất kết nối. Đã lưu local."; khi có mạng → tự retry
- [ ] BS A và BS B (cùng record) cùng gõ → BS B lưu sau → hộp thoại conflict cho BS A
FR-009 — In bộ hồ sơ + tải bản scan đã ký
Tham chiếu: DEC-007, DEC-022, DEC-024 | Ưu tiên: Must | SCR: SCR-09, SCR-10
Mô tả nghiệp vụ phần mềm:
- Vai trò: BS bấm in; Y tá scan + upload; QL CN xác nhận
- Dữ liệu:
clinical_record.status;reference_filevớitype='clinical_form_instance.scan'hoặc'clinical_record.before_after';prescriptionvớitype='prescription.scan' - Điều kiện: Bệnh án ở
Đã hoàn thànhmới in được; in xong →Đã in; scan đủ checklist case →Đã ký + scan đủ - Hành động: (1) BS bấm "In bộ hồ sơ" → render HTML từ template + variable; PDF render external; lưu HTML vào
print_invoice_htmlpattern; (2) Y tá tải bản scan: từng tờ riêng hoặc 1 file PDF cả bộ; UI cho mapping file ↔ biểu mẫu; (3) Hệ thống check checklist scan bắt buộc theo case (BA chính + cam đoan/cam kết nếu yêu cầu + phiếu dị ứng nếu bắt buộc + đơn thuốc nếu kê + phiếu theo dõi điều trị nếu có) hoặc biên bản từ chối có y tá làm chứng - Kết quả: Trạng thái chuyển
Đã in→Đã ký + scan đủkhi checklist đủ - Ngoại lệ: Tải 1 file bất kỳ KHÔNG đủ checklist → trạng thái vẫn
Đã in, banner "Còn thiếu: Phiếu cam đoan + Đơn thuốc"; KH từ chối ký → cho phép tải biên bản từ chối + y tá làm chứng → trạng tháiĐã ký + scan đủvới flagrefusal_witnessed=true
AC:
- [ ] BS hoàn thành BA + đơn thuốc + cam đoan → bấm "In bộ hồ sơ" → render PDF gồm 3 phiếu; trạng thái =
Đã in - [ ] Y tá tải 1 file PDF "ba-le-thi-huong-2026-05-02.pdf" cả bộ + UI mapping
BA chính✓ +Cam đoan✓ +Đơn thuốc✓ → trạng thái =Đã ký + scan đủ - [ ] Y tá tải duy nhất 1 file scan "ba.pdf" mapping chỉ
BA chính→ trạng thái vẫnĐã in; banner "Còn thiếu: Cam đoan, Đơn thuốc" - [ ] KH từ chối ký → Y tá tải "bien-ban-tu-choi.pdf" + check "Y tá làm chứng" → trạng thái
Đã ký + scan đủ,refusal_witnessed=true
FR-010 — Kiểm tra an toàn dị ứng
Tham chiếu: DEC-011, DEC-012 | Ưu tiên: Must | SCR: Cross-màn hình | SAFETY CRITICAL
Mô tả nghiệp vụ phần mềm:
- Vai trò: BS điền dị ứng; Hệ thống check rule
- Dữ liệu:
technical_category.allergy_risk_level(unknown/low/medium/high);allergy_check_policy;allergy_check_skip_log - Điều kiện: BA có thủ thuật xâm lấn (KT có
allergy_risk_level IN (high, unknown)) - Hành động: Trước khi cho hoàn thành BA, hệ thống check
allergy_risk_levelcủa tất cả KT trong record: (a)low/medium→ cho phép hoàn thành (cảnh báo nếu thiếu phiếu dị ứng); (b)high→ BẮT BUỘC có phiếu tiền sử dị ứng đã hoàn thành (DEC-012: lần đầu BẮT BUỘC điền mới; tái khám BS tick "không đổi" — reuse); (c)unknown→ chặn hoàn thành cho tới khi Medical Lead phân loại lại allergy_risk_level - Kết quả: BA hoàn thành OK hoặc bị chặn với lý do rõ ràng
- Ngoại lệ: Trường hợp khẩn cấp BS muốn skip → tạo
allergy_check_skip_logvới reason; không thay thế quy trình bình thường
AC:
- [ ] BA có KT "Filler Hyaluronic" (allergy_risk=high) + chưa có phiếu dị ứng → chặn "Hoàn thành"; banner "Bắt buộc điền Phiếu tiền sử dị ứng trước thủ thuật xâm lấn"
- [ ] BA có KT "Áp lạnh nitơ" (allergy_risk=low) → cho phép hoàn thành ngay
- [ ] BA có KT "Laser CO2 mới chưa phân loại" (allergy_risk=unknown) → chặn "Hoàn thành"; banner "Kỹ thuật chưa được phân loại độ rủi ro dị ứng. Vui lòng liên hệ Medical Lead"
- [ ] BS lần tái khám tick "Không đổi tiền sử dị ứng" → hệ thống reuse phiếu dị ứng cũ; cho phép hoàn thành
FR-011 — Permission 3 tầng + audit cross-branch tầng 3
Tham chiếu: DEC-008, DEC-009, DEC-010, DEC-040, DEC-043 | Ưu tiên: Must | SCR: Cross-màn hình + SCR-18 Compliance Audit | SECURITY CRITICAL
Canonical spec chi tiết:
permission-spec.mdv1.0.0 (P1-P12). FR này chỉ ghi mô tả nghiệp vụ + AC cấp cao; chi tiết action catalog, default seed, branch_mode, portal isolation, cache, migration, field masking, emergency governance, Compliance UI và 44 TC-PERM-* nằm ở permission-spec.
Mô tả nghiệp vụ phần mềm:
- Vai trò: Tất cả role có thể access clinical theo
effective_permission = role_module.actions + portal + branch_mode + backend enforcement - Dữ liệu:
role_module.actions,module_permission_action,branch_assignment,medical_record_access_log,emergency_override_session,permission_change_log, secure view masked theo tầng - Điều kiện: User request data clinical
- Hành động: (1) FE check
globalStore.hasPermission(moduleId, actionId)→ ẩn menu/button (UX); (2) BE resolve quaResolveClinicalPermission()(xempermission-spec.mdP3) — kiểm hard-deny → portal → is_pos_only → action → branch scope → view_mode → field allowlist → rate limit; (3) 3 tầng dữ liệu chỉ trả qua field allowlist matrix (xempermission-spec.mdP10); (4) Tầng 3 cross-branch chỉ quaemergency_override+ audit; (5) Multi-role user: effective = UNION; branch_mode = max scope. - Kết quả: Data trả masked theo
view_mode; mọi truy cập tầng 3 ghi log; mọi grant/revoke ghipermission_change_log - Ngoại lệ: Hard-deny pairs (
permission-spec.mdP1.3) override mọi grant — Sale có actionview_medical_detail→ backend vẫn 403; revoke giữa session → request kế tiếp 403 sau cache TTL 60s; lỗi resolver = deny không default allow
AC:
- [ ] AC-011.1 BS DL CN Cao Lãnh xem BA của KH cùng CN → 200 OK với
view_mode='full_tier3', đầy đủ field allowlist - [ ] AC-011.2 BS DL CN Cao Lãnh xem BA của KH ở CN Tân Bình II (khác CN, không emergency) → 200 OK với
view_mode='summary'; tầng 3 omit khỏi response (KHÔNG phải null — field bị remove khỏi GraphQL response) - [ ] AC-011.3 BS dùng "Mở quyền khẩn cấp" với lý do ≥30 ký tự → tạo
emergency_override_sessionTTL 1 giờ; insertmedical_record_access_logvớiaction='emergency_override'; notification ngay tới Medical Lead + QL CN + Compliance + Admin - [ ] AC-011.4 Sale CRM cố mở tầng 3 (kể cả admin gán quyền nhầm) → 403 với
DenyCode='hard_deny'+ log warning + alert Compliance - [ ] AC-011.5 Admin revoke
view_medical_detailcủa BS A → trong tối đa 60s (TTL) hoặc ngay (WS push) → request kế tiếp của BS A trả 403; FE force refetch + toast "Quyền của bạn đã thay đổi. Vui lòng tải lại trang." - [ ] AC-011.13 Multi-role user (BS + Manager) →
effective_permission= UNION action;branch_mode= max scope (all > multi_branch > branch > self);is_pos_onlychỉ true khi MỌI role POS-only - [ ] AC-011.14 User
is_pos_only=truecố mở Admin/CRM URL → server redirect về/pos+ log warning; cố call API ngoài POS → 403DenyCode='pos_only_violation' - [ ] AC-011.15
branch_mode='self'chỉ thấy record do user tạo / phụ trách (primary_doctor_id=$user OR created_by=$user) - [ ] AC-011.16
branch_mode='multi_branch'thấy union record CN trongbranch_assignment; CN ngoài assignment → tầng 1+2 only - [ ] AC-011.17 Emergency override rate limit: ≤2/giờ (cảnh báo), ≤5/ngày (block), ≤15/tuần (force compliance review); session TTL 1 giờ; cron auto-expire mỗi 5 phút
- [ ] AC-011.18 Cache TTL ≤60s sliding ở Redis BE; FE WS push hoặc TTL 60s; mọi mismatch FE ↔ BE → BE truth thắng + FE force refetch
- [ ] AC-011.19 Migration backward-compat: existing role business (BS/Y tá/Sale/QL CN/Admin/Ops/Medical Lead) tự động được seed 22 action mới theo default seed matrix
permission-spec.mdP2.1; user không có role business chuẩn → output report cho admin review (KHÔNG tự seed) - [ ] AC-011.20 Compliance officer + Admin/Ops + Medical Lead xem
medical_record_access_logqua SCR-18 với filter user/CN/action/sensitivity/anomaly; export Excel theopermission-spec.mdP11.3; Day-1 hoặc Phase 2 tuỳ PD-PERM-004
FR-012 — Sổ khám bệnh + Sổ thủ thuật
Tham chiếu: DEC-014, DEC-015 | Ưu tiên: Must | SCR: SCR-11, SCR-12
Mô tả nghiệp vụ phần mềm:
- Vai trò: QL CN, Admin/Ops xem; export
- Dữ liệu: Derive từ
clinical_record + appointment + product/technical_category - Điều kiện: Có quyền
clinical_record.export_visit_log - Hành động: (1) Sổ khám bệnh: list lượt khám trong ngày/tháng theo CN; STT theo FORMULA-002; cột: STT, Ngày, Mã BA, Tên KH, BS, Chẩn đoán chính, Trạng thái BA; (2) Sổ thủ thuật: list ca có KT thủ thuật; STT theo FORMULA-003; thêm cột: KT, Vật tư, Biến chứng (nếu có); export Excel async > 1000 dòng (chunk 100)
- Kết quả: Table trên màn + export Excel
- Ngoại lệ: User không có
view_medical_detail→ cột "Chẩn đoán chính" hiển thị "—"
AC:
- [ ] QL CN Cao Lãnh xem sổ khám tháng 04/2026 → table 147 lượt khám với STT
DVA-CL-00001/2026..DVA-CL-00147/2026 - [ ] Sổ thủ thuật chỉ list ca có KT thủ thuật → 89 ca trong tháng → STT
DVA-CL-TT-00001/2026..00089/2026 - [ ] Export Excel sổ khám tháng có 1.500 dòng → async; user nhận notification "Đã xuất file. Bấm để tải về."
- [ ] Sale (không có
view_medical_detail) export sổ khám → cột "Chẩn đoán" hiển thị "—" thay vì ICD-10
FR-013 — Notification "cần BA" + "BA thiếu"
Tham chiếu: DEC-013 | Ưu tiên: Must | SCR: Cross-màn hình
Mô tả nghiệp vụ phần mềm:
- Vai trò: Hệ thống event trigger; BS, Y tá, QL CN nhận
- Dữ liệu:
notification_template7 trigger code mới,notification_queue - Điều kiện: Event xảy ra (order insert, BA quá hạn, scan thiếu, ...)
- Hành động: Insert
notification_templatecho 7 trigger:noti_medical_record_incomplete,_needs_print,_needs_scan,_allergy_warning,_end_of_day,_emergency_override,_handoff_created; event handler enqueue + scheduler send qua ZNS/SMS/Push; dedupe keyclinical_record_{id}_{action} - Kết quả: BS/Y tá/QL nhận thông báo kịp thời
- Ngoại lệ: Push deeplink chỉ chứa
record_id+ branch (không chẩn đoán/form/scan); Sale không nhận notification clinical
AC:
- [ ] Lễ tân tạo đơn dịch vụ "Filler Hyaluronic" cho khách Lê Hương → event
order_inserttriggernoti_medical_record_incomplete→ BS DL CN Cao Lãnh nhận push "Có 1 BA cần tạo cho khách Lê Hương — bấm để mở Bàn việc bác sĩ" - [ ] BA "Bản nháp" quá 24h → cron
cronClinicalRecordReminderenqueue thông báo cho BS phụ trách - [ ] Cuối ngày 19:30 (trước cutoff 20:00) → cron gửi reminder "Còn 5 BA chưa hoàn thành tại CN Cao Lãnh"
- [ ] BS A trigger
Mở quyền khẩn cấp→ notification ngay tới Medical Lead + Ops; deeplink chỉ córecord_id, không có chẩn đoán
FR-014 — Sequence generator generic
Tham chiếu: DEC-013, DEC-014, DEC-015 | Ưu tiên: Must | SCR: Cross-màn hình
Mô tả nghiệp vụ phần mềm:
- Vai trò: Hệ thống (action handler
generateSequence) - Dữ liệu:
sequence_generator(entity_type, branch_id, year, next_value) - Điều kiện: Cần sinh STT/mã mới
- Hành động: Action handler atomically increment + return:
(entity_type='clinical_profile', branch_id=X, year=2026)→ next NNNNN; áp dụng cho FORMULA-001 (mã BA chính), FORMULA-002 (STT sổ khám), FORMULA-003 (STT sổ thủ thuật) - Kết quả: Số liên tục, không trùng, không skip (atomic)
- Ngoại lệ: Concurrent insert → row lock; sequence overluồng 99999 → fallback 6 chữ số sau 99999
AC:
- [ ] 100 BA tạo concurrent tại CN Cao Lãnh → 100 mã liên tục
DVA-DL-CL-2026-00001..00100, không trùng, không skip - [ ] Đầu năm 2027 sinh STT sổ khám → reset về
DVA-CL-00001/2027; mã BA chính (FORMULA-001) vẫn tiếpDVA-DL-CL-2027-00001(không reset, format có year) - [ ] STT sổ thủ thuật chỉ sinh khi
clinical_recordcó ít nhất 1 product với KTtype='procedure'
FR-015 — Kiểm tra sẵn sàng + an toàn phát hành per CN
Tham chiếu: DEC-031, DEC-041 | Ưu tiên: Must | SCR: SCR-04f
Mô tả nghiệp vụ phần mềm:
- Vai trò: Admin/Ops phát hành; Hệ thống tự kiểm tra
- Dữ liệu:
clinic_module_publication.readiness_snapshot(JSONB),clinic_module_publication.status/effective_at - Điều kiện: Module ở
setup_drafthoặcpaused - Hành động: Wizard bước 6 chạy 10 kiểm tra sẵn sàng check: R-01 Loại PK · R-02 Giấy phép còn hạn · R-03 Danh mục KT đủ · R-04 Allergy_risk_level không còn
unknown· R-05 Classification 100% (không cònunclassified) · R-06 Phân quyền (BS/Y tá/QL CN) · R-07 Print preview test · R-08 BA demo test · R-09 Support owner · R-10 Legal/SYT artifact + scanner/printer/upload-account; mỗi mục đạt/không đạt; chỉ đạt 100% mới cho phát hành - Kết quả:
readiness_snapshotlưu trạng thái 10 mục;status='ready_to_publish'; CTA "Phát hành (effective DD/MM/YYYY HH:mm)" mở - Ngoại lệ: R-xx không đạt → highlight + deeplink sang màn cần sửa; user fix xong quay lại bước 6 re-check
AC:
- [ ] CN Cao Lãnh wizard bước 6 → 9/10 đạt; R-04 không đạt (1 KT vẫn
unknown) → highlight đỏ R-04 + deeplink sang Danh mục kỹ thuật → quay lại - [ ] R-04 fixed → re-check → 10/10 đạt → CTA "Phát hành" mở
- [ ] Admin chọn effective
02/05/2026 09:00→clinic_module_publication.effective_at='2026-05-02 09:00:00+07'; trạng tháischeduled - [ ] Tới 09:00 ngày 02/05 → cron auto chuyển
scheduled → live; vận hành gate (DEC-041) bật
FR-016 — Trang xem an toàn (Sale) + Phiếu chuyển bác sĩ tư vấn
Tham chiếu: DEC-009, DEC-032 | Ưu tiên: Must | SCR: SCR-13
Mô tả nghiệp vụ phần mềm:
- Vai trò: Sale CRM xem; Sale tạo handoff; BS nhận
- Dữ liệu: Secure view
clinical_sales_view(chỉ tầng 1+2 đã diễn giải an toàn);clinical_sales_handoff(sale_id, doctor_id, customer_id, branch_id, expectations, safe_notes); dictionarysafe_alert_level/code/text - Điều kiện: Sale có quyền
clinical_sales.view_safe_summary; Sale CRM portal - Hành động: (1) Trang xem an toàn (Sale) hiện thông tin tóm tắt: dị ứng (
safe_alerttừ dictionary), bệnh nền (label an toàn), số lượt khám, lịch sử dịch vụ, count BA — KHÔNG có chẩn đoán/form/scan/ảnh y tế; (2) CTA "Chuyển bác sĩ tư vấn" → form handoff: chọn BS, ghi expectations + safe notes; (3) BS nhận notificationnoti_handoff_created - Kết quả: Sale tư vấn đúng ngữ cảnh an toàn; BS nhận phiếu chuyển
- Ngoại lệ: Sale cố click vào diagnosis/form/scan → 403; safe note có chẩn đoán/y lệnh → backend từ chối với regex check
AC:
- [ ] Sale CRM xem khách Lê Hương → màn hiển thị: "Dị ứng: Có 1 cảnh báo (chuyển BS để xem chi tiết)"; "Lịch sử: 12 lượt khám tại Cao Lãnh"; KHÔNG hiện ICD-10 hay diagnosis text
- [ ] Sale bấm "Chuyển bác sĩ tư vấn" → form chọn BS DL CN Cao Lãnh; ghi expectations "Khách muốn liệu trình trị mụn"; safe note "Khách có ngân sách 5tr"
- [ ] Sale ghi safe note "Khách bị mụn trứng cá nặng L70.0" → backend từ chối 422 "Ghi chú không được chứa thuật ngữ y khoa hoặc mã ICD-10"
- [ ] BS nhận notification + mở handoff → thấy expectations + safe notes; CTA "Đặt lịch khám" sang luồng tạo appointment
FR-017 — Bàn việc bác sĩ với 6 nhóm việc
Tham chiếu: DEC-033 | Ưu tiên: Must | SCR: SCR-14
Mô tả nghiệp vụ phần mềm:
- Vai trò: BS, Y tá hỗ trợ
- Dữ liệu: Server-side query
doctor_workbench_viewtrả 6 bucket:need_record(cần tạo BA),draft(BA nháp),need_print(cần in),need_scan(cần scan),sales_handoff(handoff Sale chờ),intake_review(Phiếu khách tự khai chờ nhận) - Điều kiện: BS có quyền
doctor_workbench.access; CN ởlive - Hành động: Mỗi bucket có
task_keyổn định,queue_owner_type='doctor',queue_owner_id={BS}; CTA tiếp theo theo loại task;need_recordchỉ sinh khi appointment/order thật sự có dịch vụmapped_requires_ba - Kết quả: BS thấy danh sách việc trong ngày; bấm task → luồng tương ứng (tạo BA / mở BA nháp / in / scan / handoff / intake)
- Ngoại lệ: Dịch vụ
unclassified→ KHÔNG sinhneed_recordtask (tránh false-positive); cảnh báo Ops thay vào đó (FR-019)
AC:
- [ ] BS DL CN Cao Lãnh sáng 02/05/2026 mở Bàn việc bác sĩ → 6 bucket với count:
need_record=3,draft=2,need_print=1,need_scan=4,sales_handoff=1,intake_review=2 - [ ] BS bấm task
need_recordcho khách Lê Hương → chuyển sang luồng tạo BA DL với appointment/customer pre-fill - [ ] Lễ tân tạo đơn với dịch vụ
unclassified→ KHÔNG sinhneed_recordtask; thay vào đó cảnh báo Ops - [ ] BS B (khác CN) cố vào Bàn việc bác sĩ CN Cao Lãnh → query trả empty (branch scope)
FR-018 — Phiếu khách tự khai (token 15 phút)
Tham chiếu: DEC-034 | Ưu tiên: Should | SCR: SCR-15
Mô tả nghiệp vụ phần mềm:
- Vai trò: Lễ tân/Y tá mở session; KH điền; BS review/nhận
- Dữ liệu:
customer_clinical_intake(token, customer_id, branch_id, appointment_id, expires_at, form_data, source_type='customer_intake');clinical_form_instance.source_type/source_ref_id - Điều kiện: KH đến quầy có lịch hẹn; appointment đã tạo
- Hành động: (1) Lễ tân/Y tá bấm "Mở phiên khách tự khai" cho appointment cụ thể → server tạo token 15 phút + URL
/p/customer-clinical-intake/{token}; (2) Mở URL trên tablet/quầy; KH điền dị ứng/bệnh nền/thuốc đang dùng (tier 1+2 only); KH gửi qua token (KHÔNG gửi tự docustomer_id/branch_id); server validate appointment/record cùng KH + CN; (3) BS mở BA cho KH → thấy phiếu khách tự khai chờ review; bấm "Nhận vào hồ sơ" → ghi vàoclinical_form_instancevớisource_type='customer_intake'+source_ref_id={intake.id}; auditmedical_record_access_log - Kết quả: Giảm thời gian BS nhập hành chính; an toàn dị ứng nhanh hơn
- Ngoại lệ: Token quá 15 phút → 410 Gone, KH phải nhờ Lễ tân mở lại; KH trên tablet đổi sai KH/CN → server từ chối 422
AC:
- [ ] Lễ tân CN Cao Lãnh mở session cho appointment khách Lê Hương 14:30 → tablet hiển thị form intake cho Lê Hương
- [ ] KH điền 5 dị ứng + 2 bệnh nền + 3 thuốc đang dùng → gửi qua token → server lưu
customer_clinical_intake.form_data - [ ] Token hết hạn sau 15 phút → KH bấm gửi → 410 "Phiên đã hết hạn. Vui lòng nhờ lễ tân mở lại."
- [ ] BS mở BA cho Lê Hương → thấy "Phiếu khách tự khai (chờ review)"; bấm "Nhận vào hồ sơ" → form BA prefill 5 dị ứng + 2 bệnh nền;
source_type='customer_intake'
FR-019 — Trang điều phối phòng khám + Chốt ngày phòng khám
Tham chiếu: DEC-035, DEC-036 | Ưu tiên: Must | SCR: SCR-16, SCR-17
Mô tả nghiệp vụ phần mềm:
- Vai trò: Admin/Ops xem toàn chuỗi; QL CN xem CN mình + chốt ngày
- Dữ liệu:
clinic_ops_dashboard_view(drift cấu hình, BA tồn, scan thiếu);clinic_daily_close(branch_id, date, draft_count, missing_scan_count, escalated_count, closed_by, closed_at);branch_technical_config.close_cutoff_time/close_reminder_times(mặc định 20:00 Asia/Ho_Chi_Minh) - Điều kiện: Admin/Ops có
clinic_ops.view_all_dashboard; QL CN cóclinic_ops.view_branch_dashboard - Hành động: (1) Trang điều phối phòng khám: theo dõi trạng thái CN, dịch vụ
unclassified, KTunknown, BA nháp quá hạn, bản in chưa scan, mở quyền khẩn cấp, drift kiểm tra sẵn sàng; (2) Chốt ngày: cron đọc cutoff per CN; pre-cutoff reminder; tới cutoff → croncronClinicalDailyCloseghi nhậndraft_count + missing_scan_count; QL CN bấm "Chốt ngày" → hộp thoại xác nhận "Còn 5 BA nháp + 3 BA chưa scan. Bạn xác nhận chốt?" → logclinic_daily_close; nếu còn P0 chưa giải quyết → báo Ops/Medical Lead - Kết quả: Ops kiểm soát rollout chuỗi; QL CN có gate cuối ngày
- Ngoại lệ: Cron miss → manual close vẫn được; rollback
paused→ cron skip CN
AC:
- [ ] Ops mở Trang điều phối → thấy 12 CN active; CN Cao Lãnh có cảnh báo "3 dịch vụ chưa phân loại"; CN Tân Bình II có "5 BA nháp quá hạn"
- [ ] Pre-cutoff 19:30 → cron gửi reminder "Còn 5 BA chưa hoàn thành tại CN Cao Lãnh trước 20:00"
- [ ] Đúng 20:00 → cron ghi nhận trạng thái; QL CN bấm "Chốt ngày" → hộp thoại xác nhận với số liệu → log
clinic_daily_close.closed_at=20:15 - [ ] Còn 1 BA P0 chưa scan → cron gửi cảnh báo Ops + Medical Lead qua notification
A5) Vòng đời (Lifecycle)
LIFECYCLE-001 — Module Phòng khám per CN
| Trạng thái | Ý nghĩa nghiệp vụ | Điều kiện vào | Điều kiện ra | Terminal |
|---|---|---|---|---|
off | Module chưa bật | Trạng thái mặc định | Admin bật | Không |
setup_draft | Đang cấu hình | Bật module | Wizard đạt | Không |
ready_to_publish | Đã đạt kiểm tra sẵn sàng, chờ Admin phát hành | Wizard đạt | Admin phát hành | Không |
scheduled | Đã phát hành, chờ effective_at | Admin chọn effective | Tới effective | Không |
live | Đang hoạt động vận hành | Effective_at đến | Admin tạm dừng | Không |
paused | Tạm dừng vận hành | Admin tạm dừng | Admin tiếp tục/sửa | Không |
| Từ | Event | Điều kiện | Sang | Giải thích |
|---|---|---|---|---|
off | mở_module | Admin role + branch type clinic-eligible | setup_draft | Bật cấu hình |
setup_draft | wizard_complete | 6 bước + R-01..R-10 đạt | ready_to_publish | Sẵn sàng phát hành |
ready_to_publish | publish_now | Admin role + effective_at đã set | live | Phát hành ngay |
ready_to_publish | publish_scheduled | Admin role + effective_at tương lai | scheduled | Lập lịch phát hành |
scheduled | cron_effective_reached | Cron tới effective_at | live | Auto chuyển đang hoạt động |
live | pause | Admin role + lý do | paused | Tạm dừng |
paused | resume | Admin role | live | Tiếp tục |
paused | resume_with_changes | Admin role + sửa cấu hình | ready_to_publish | Re-check trước khi đang hoạt động lại |
LIFECYCLE-002 — Bệnh án lượt khám
| Từ | Event | Guard | Sang | Side effects |
|---|---|---|---|---|
draft | complete | Allergy check đạt + ICD-10 primary có | completed | Notification BS, log audit |
completed | print | Có quyền print | printed | Render PDF, lưu HTML, log |
printed | upload_scan | Y tá có quyền upload_scan + checklist scan đủ theo case | signed | Update flag, notification QL CN |
printed | correct_after_print | BS có quyền edit_medical_form | superseded (bản cũ) + printed (bản v2) | Tạo bản v2; bản cũ KHÔNG xóa |
signed | archive_after_retention | Cron retention 1 năm | archived | Move file scan sang cold storage |
Quy tắc cứng: không cho xóa BA y tế đã
completed/printed/signed(DEC-023). Sửa sai sau in = in bản v2; bản cũ giữ làm audit.
LIFECYCLE-003 — Phiếu khách tự khai
A6) Giả định và rủi ro
Giả định
| ID | Giả định | Phụ trách xác nhận |
|---|---|---|
| ASM-001 | Hot MinIO storage 1 năm đủ + cold archive 9 năm OK với cost projection | Infra Lead |
| ASM-002 | ICD-10 bản 2015 BYT đủ cho pilot 30 ngày | Medical Lead |
| ASM-003 | Mỗi CN pilot có scanner/printer/account upload sẵn sàng | Ops Lead |
| ASM-004 | Sở YT Đồng Tháp + TPHCM chấp nhận luồng giấy ký tay + scan reference | Legal |
| ASM-005 | Pilot 2 CN trong 30 ngày đủ data để đánh giá đại diện | PO |
| ASM-006 | Sale chấp nhận không xem tầng 3 | Sale Lead |
| ASM-007 | BS phòng khám thực tế chấp nhận autosave 30s và Bàn việc bác sĩ | Medical Lead + 2 BS pilot |
Rủi ro
| ID | Rủi ro | Ảnh hưởng | Xác suất | Cách giảm thiểu |
|---|---|---|---|---|
| RSK-001 | Appointment.OrderItemID non-pointer → silent bug walk-in | Cao | Cao | Refactor *uuid.UUID + null-guard 5 call site (Phase 0 blocker) |
| RSK-002 | Sai phân quyền tầng 3 → Sale xem được chẩn đoán | Cao | Trung bình | Permission v2 backend enforce; secure view masked; QA test grant/revoke/portal split |
| RSK-003 | Raw clinical tables expose cho vận hành user | Cao | Trung bình | DEC-040 — không cấp raw select/mutation; secure view/action; security test metadata |
| RSK-004 | Allergy unknown bị hiểu là medium → bỏ qua | Cao | Thấp | Trạng thái mặc định chặn + bắt Medical Lead phân loại trước khi đang hoạt động |
| RSK-005 | Đã ký + scan đủ hiểu sai = chỉ cần 1 scan | Cao | Trung bình | Checklist scan theo case; QA phủ refusal evidence |
| RSK-006 | Legal/SYT không xác nhận luồng giấy ký + scan | Cao | Thấp | Văn bản xác nhận trước go-live; NO-GO nếu chỉ xác nhận miệng |
| RSK-007 | Scope creep regression sang module không liên quan | Trung bình | Cao | Impact Boundary Matrix v2.0 (DEC-044) làm scope lock; QA D6 smoke regression |
| RSK-008 | BS không dùng Bàn việc bác sĩ nếu có task giả | Trung bình | Cao | need_record chỉ join dịch vụ mapped_requires_ba; QA test false-positive |
| RSK-009 | Bản scan trễ → hồ sơ pháp lý chưa hoàn chỉnh | Trung bình | Cao | Chốt ngày + reminder + escalation |
| RSK-010 | Rollback chạy down migration sau khi đã có BA thật | Trung bình | Thấp | D0+ chỉ pause/code rollback giữ DB; down migration chỉ pre-D0 |
A7) Bảng thuật ngữ
Tham chiếu canonical:
SOURCE_OF_TRUTH.mdmục 0 (34 thuật ngữ A1–E34). PRD A7 chỉ ghi tóm tắt cho người đọc PRD.
| Tiếng Việt | EN/code | Định nghĩa | Phân biệt với |
|---|---|---|---|
| Hồ sơ bệnh án chính | clinical_profile | Hồ sơ ổn định theo KH/CN/loại PK; giữ mã BA chính | ≠ Bệnh án lượt khám |
| Bệnh án lượt khám | clinical_record | Bản ghi y tế cho 1 appointment + form_type | ≠ Hồ sơ bệnh án chính / ≠ Lượt khám |
| Lượt khám | appointment | 1 lần KH đến PK; có thể có 0–2 bệnh án lượt khám | — |
| Phiếu biểu mẫu | clinical_form_instance | 1 tờ biểu mẫu cụ thể trong bộ hồ sơ | ≠ Khuôn biểu mẫu |
| Khuôn biểu mẫu | form_template | Định nghĩa schema JSON | ≠ Phiếu biểu mẫu |
| Danh mục kỹ thuật | technical_category | Mã + tên KT do Sở YT cấp phép cho CN | ≠ Dịch vụ thương mại |
| Phân loại dịch vụ — kỹ thuật | service_clinical_classification | DV thương mại theo CN: cần BA / không cần BA / chưa phân loại | — |
| Phòng khám | branch.features.clinic_enabled | Module bật/tắt theo CN | ≠ Chi nhánh |
| Bản phát hành phòng khám | clinic_module_publication | Bản ghi quản lý phát hành/tạm dừng module per CN | ≠ Bật/tắt |
| Bàn việc bác sĩ | doctor_workbench_view | Màn gom 6 nhóm việc BA trong ngày | — |
| Phiếu khách tự khai | customer_clinical_intake | Dữ liệu KH tự khai trước khám (token 15 phút) | ≠ Phiếu biểu mẫu BA |
| Trang xem an toàn (Sale) | (secure view) | Sale xem tầng 1+2 đã diễn giải an toàn | ≠ Hồ sơ bệnh án chính |
| Phiếu chuyển bác sĩ tư vấn | clinical_sales_handoff | Sale chuyển khách sang BS | — |
| Trang điều phối phòng khám | clinic_ops_dashboard_view | Dashboard rollout toàn chuỗi | ≠ Branch Detail |
| Chốt ngày phòng khám | clinic_daily_close | Checklist cuối ngày | ≠ Go-live checklist |
| Tải bản scan đã ký | upload_scan action | Tải bản scan đã ký lên hệ thống | ≠ In / ≠ Tải ảnh trước-sau |
| Ảnh trước–sau điều trị | before_after (file type) | Ảnh y tế gắn theo bệnh án (tầng 3) | ≠ Bản scan / ≠ treatment-images (CRM) |
| Mở quyền khẩn cấp | emergency_override | Tạm mở tầng 3 khác CN + audit | — |
| Kiểm tra sẵn sàng | readiness_snapshot | Checklist 100% mục trước phát hành | ≠ Go-live checklist tổng |
| Tầng 1/2/3 | tier_1/2/3 | Phân tầng dữ liệu nhạy cảm | — |
A8) Công thức nghiệp vụ
A8 là canonical (PO sở hữu). Dev Spec C3 chỉ ghi SQL implementation delta, ref A8.
FORMULA-001: Mã hồ sơ BA chính
- Mô tả: Định danh duy nhất cho hồ sơ y tế ổn định của 1 KH tại 1 CN theo loại PK.
- Công thức:
DVA-[type]-[branch_code]-[year]-[sequence_5_digit] - Biến số:
type:'DL'hoặc'TM'— nguồnclinical_profile.form_typebranch_code: mã ngắn CN (VD:CL,TB2) — nguồnbranch.codeyear: năm tạo profile đầu tiên — nguồnclinical_profile.created_atYEARsequence_5_digit: monotonic per CN+type, padded 5 chữ số; không reset theo năm
- Đơn vị: chuỗi ký tự
- Ví dụ: KH đầu tiên tạo BA DL tại CN Cao Lãnh năm 2026 →
DVA-DL-CL-2026-00001 - Trường hợp cá biệt:
- 1 KH có dịch vụ DL+TM tại cùng CN → 2 mã (khác
type) - KH chuyển CN khác → mã mới tại CN đó (khác
branch_code) - Sequence overluồng 99999 → fallback 6 chữ số sau 99999
- 1 KH có dịch vụ DL+TM tại cùng CN → 2 mã (khác
- Reset: Không reset
FORMULA-002: STT sổ khám bệnh
- Mô tả: Số thứ tự lượt khám trong sổ khám của CN, reset theo năm.
- Công thức:
DVA-[branch_code]-[sequence_5_digit]/[year] - Biến số:
branch_code←branch.codeyear←appointment.fromYEARsequence_5_digit: STT trong năm
- Ví dụ: Lượt khám thứ 147 năm 2026 tại CN Cao Lãnh →
DVA-CL-00147/2026 - Reset: 00:00 ngày 1/1 mỗi năm
FORMULA-003: STT sổ thủ thuật
- Mô tả: Số thứ tự ca có KT thủ thuật, reset theo năm.
- Công thức:
DVA-[branch_code]-TT-[sequence_5_digit]/[year] - Biến số: Như FORMULA-002
- Ví dụ: Ca thủ thuật thứ 89 năm 2026 tại CN Cao Lãnh →
DVA-CL-TT-00089/2026 - Trường hợp cá biệt: Chỉ sinh khi
clinical_recordcó ít nhất 1 product với KTtechnical_category.type='procedure'. Ca không thủ thuật không có STT này. - Reset: Theo năm
FORMULA-004: % BA hoàn thành đúng ngày
- Mô tả: Tỉ lệ BA bấm "Hoàn thành" cùng ngày với
appointment.from. - Công thức:
count_completed_same_day / count_total_appointment_need_ba × 100 - Biến số:
count_completed_same_day: sốclinical_recordvớicompleted_at::date = appointment.from::datecount_total_appointment_need_ba: số appointment/form_type trong ngày có product mapping KT
- Đơn vị: % (2 chữ số thập phân, dấu phẩy:
90,00%) - Ví dụ: 90 BA hoàn thành / 100 appointment cần BA →
90,00% - Trường hợp cá biệt:
- Appointment không cần BA (
explicitly_no_ba) hoặcvisit_only=true→ exclude khỏi denominator - Product
unclassified→ KHÔNG được tính là "không cần BA"; phải vào alert/config backlog - Walk-in luôn có appointment; nếu
appointment.fromchưa set thì dùngclinical_record.created_at::datevà flag data quality - BA hoàn thành qua ngày (VD: khám 18h, hoàn thành 22h) → vẫn tính same day
- Denominator = 0 → hiển thị
—
- Appointment không cần BA (
FORMULA-005: Thời gian TB BS điền 1 BA
- Mô tả: Average duration từ tạo
clinical_recordtớicompleted_at. - Công thức:
AVG(completed_at - created_at) WHERE status IN ('completed','printed','signed') - Đơn vị: phút (integer)
- Ví dụ: 100 BA, tổng 900 phút → 9 phút/BA
- Trường hợp cá biệt:
- BA draft quá 24h (BS quên) → exclude khỏi average
- BA hoàn thành <30s → flag outlier
FORMULA-006: Tỉ lệ BA đủ chữ ký + scan đủ
- Mô tả: % BA đạt trạng thái
Đã ký + scan đủtheo checklist case. - Công thức:
count_signed / count_completed × 100 - Biến số:
count_signed←clinical_record WHERE status='signed'count_completed←clinical_record WHERE status IN ('completed','printed','signed')
- Đơn vị: % (2 chữ số thập phân)
- Trường hợp cá biệt:
- BA refusal (KH từ chối ký) có biên bản y tá làm chứng → tính là
signedvới flagrefusal_witnessed=true - Denominator = 0 →
—
- BA refusal (KH từ chối ký) có biên bản y tá làm chứng → tính là
FORMULA-007: Allergy risk level → action
- Mô tả: Map
technical_category.allergy_risk_level→ action khi hoàn thành BA. - Công thức (decision table):
allergy_risk_level | Action |
|---|---|
low | Cho hoàn thành; cảnh báo nếu thiếu phiếu dị ứng |
medium | Cho hoàn thành; bắt buộc có phiếu dị ứng (lần đầu) hoặc tick "không đổi" (tái khám) |
high | BẮT BUỘC có phiếu dị ứng đã hoàn thành; nếu không → chặn "Hoàn thành" |
unknown | chặn "Hoàn thành" cho tới khi Medical Lead phân loại lại |
- Trường hợp cá biệt: Khẩn cấp → BS có thể tạo
allergy_check_skip_logvới reason; không thay thế quy trình bình thường
A11) Truy vết (Traceability)
Mapping FR → Component FE → Artifact BE → TC. Canonical:
dev-spec.mdC11.
| FR | Component FE chính | Artifact BE chính | QA TC |
|---|---|---|---|
| FR-001 | BranchDetail.tsx (tab Phòng khám) | clinic_module_publication table + enableClinicModule action | TC-001-* (4 TC) |
| FR-002 | BranchDetailClinicConfig.tsx (5-step wizard) | branch_technical_config, technical_category, service_clinical_classification | TC-002-* (4 TC) |
| FR-003 | BranchDetailClinicConfig.tsx step 4 | service_clinical_classification | TC-003-* (4 TC) |
| FR-004 | AppointmentForm.tsx (walk-in toggle) | Appointment.OrderItemID refactor + null-guard | TC-004-* (4 TC) [CRITICAL] |
| FR-005 | ClinicalRecordFormDL.tsx | clinical_record, clinical_form_instance, icd10_code | TC-005-* (5 TC) |
| FR-006 | ClinicalRecordFormTM.tsx (4 phân hệ) | Tương tự FR-005 | TC-006-* (5 TC) |
| FR-007 | SharedFormsDialog.tsx | form_template shared, prescription | TC-007-* (6 TC) |
| FR-008 | (autosave hook) | update_clinical_form_instance mutation | TC-008-* (5 TC) |
| FR-009 | PrintClinicalRecordDialog.tsx, UploadScanDialog.tsx | printClinicalRecord, uploadClinicalScan actions; reference_file | TC-009-* (6 TC) |
| FR-010 | (cross-màn hình guard) | allergy_check_policy, allergy_check_skip_log | TC-010-* (6 TC) [SAFETY CRITICAL] |
| FR-011 | (cross-màn hình) | Permission v2 secure view + medical_record_access_log | TC-011-* (11 TC) [SECURITY CRITICAL] |
| FR-012 | MedicalVisitLog.tsx, ProcedureLog.tsx | Hasura view derive từ clinical_record | TC-012-* (4 TC) |
| FR-013 | (notification UI) | 7 notification trigger mới + event handlers | TC-013-* (3 TC) |
| FR-014 | — | sequence_generator + action generateSequence | TC-014-* (4 TC) |
| FR-015 | BranchDetailClinicConfig.tsx step 6 | clinic_module_publication.readiness_snapshot + cron cronEffectiveReached | TC-015-* (5 TC) |
| FR-016 | CustomerSalesSafeView.tsx, SalesHandoffDialog.tsx | clinical_sales_view secure view + clinical_sales_handoff | TC-016-* (7 TC) |
| FR-017 | DoctorWorkbench.tsx | doctor_workbench_view query | TC-017-* (5 TC) |
| FR-018 | CustomerClinicalIntakeForm.tsx (POS portal) | customer_clinical_intake + token validation | TC-018-* (6 TC) |
| FR-019 | ClinicOpsDashboard.tsx, ClinicDailyCloseDialog.tsx | clinic_ops_dashboard_view, clinic_daily_close + cron cronClinicalDailyClose | TC-019-* (5 TC) |
Tổng: 99 core test case (xem qa-test-plan.md D2 chi tiết).
A12) Ma trận ranh giới ảnh hưởng (Impact Boundary Matrix)
Canonical:
SOURCE_OF_TRUTH.mdmục 2.4. PRD A12 ref ngắn.
Ảnh hưởng trực tiếp: Settings/Branch Detail · Permission v2 · Appointment · POS/Order · Product/DV · Customer/CRM · Clinical (BUILD) · Reference File/MinIO · Print/PDF · Notification v2 · Export · Bàn việc bác sĩ (BUILD) · Trang xem an toàn (Sale) (BUILD) · Phiếu khách tự khai (BUILD) · Trang điều phối + Chốt ngày (BUILD).
Ảnh hưởng gián tiếp (smoke regression bắt buộc): Dashboard/Report chung · Ticket/Task/Project · Mobile/Push · Export API · Support/Incident · Complaint/CSKH.
Không ảnh hưởng Day-1 (smoke regression chứng minh): Wallet · Salary/KPI/Timekeeping · Affiliate/Achievement/Gamification · CMS/Geo/Conversation · Finance/P&L · Warehouse/Inventory.
QA D6 phủ regression theo 3 lớp này.
End of PRD v2.0.0. File này là quy ước nghiệp vụ chuẩn. Mọi DEC/FR/AC được truyền xuống ui-spec.md (B sections) + dev-spec.md (C sections) + qa-test-plan.md (D sections). Nếu tài liệu dẫn xuất xung đột với PRD A8 (công thức), PRD thắng; nếu xung đột với SoT mục 0 (thuật ngữ canonical), SoT thắng.