KB-7898 rev 2

Điều 31+ — Gương Soi Độc Lập (Independent Verification Mirror) v1.1

7 min read Revision 2
architecturedieu31-plusindependent-verificationmirrorplaywright-vpspg-directself-hosted

Điều 31+ — Gương Soi Độc Lập (Independent Verification Mirror)

Version: v1.1 draft | Ngày: 2026-03-25 | Tác giả: Anh Huyên (ý tưởng + phương pháp luận) + Claude (phân tích kỹ thuật) TD: TD-359 | Ưu tiên: 🔴 Sau khi Điều 31 Phase B-C hoàn thành


I. VẤN ĐỀ

Hiện tại hệ thống có 2 luật kiểm tra: Điều 26 (Luật Đếm) và Điều 31 (Toàn Vẹn). Cả hai đều so sánh PG ↔ Nuxt API endpoint.

Điểm mù:

  1. Nuxt API → Màn hình: Nếu Vue code lỗi, hiển thị sai → không ai biết
  2. Nếu Điều 26 VÀ Điều 31 cùng lúc sai giống nhau → không phát hiện được
  3. Toàn bộ dữ liệu đi qua Directus (trung gian) → nếu Directus lỗi, cả 2 luật cùng sai

Yêu cầu Anh Huyên: "Kiểm soát 100% đúng nghĩa. Sai là biết luôn. Kể cả 2 luật cùng không chạy, user vẫn được biết. Tôi không thể yên tâm khi hệ thống sai hay đúng mà tôi không tự biết."


II. MÔ HÌNH — GƯƠNG SOI ĐỘC LẬP

Nguyên lý

Kênh kiểm chứng PHẢI hoàn toàn độc lập với kênh chính:

  • Không dùng chung code
  • Không dùng chung đường dẫn dữ liệu
  • Không phụ thuộc dịch vụ bên thứ 3 (GitHub, v.v.) cho chức năng cốt lõi

Dòng chảy dữ liệu hiện tại (kênh chính)

PG → Directus → Nuxt API endpoint → Nuxt Vue UI → Màn hình

Con người bấm "Refresh" trên Registries → Nuxt gọi API → API gọi Directus → Directus đọc PG → số hiển thị.

Dòng chảy Gương Soi (kênh độc lập — KHÔNG dùng Directus)

PG ──(trực tiếp)──→ Nuxt endpoint riêng → Ô gương soi trên Registries
                                                    ↑
PG ──(trigger)──→ Playwright trên VPS → Đọc số thật trên màn hình → So sánh

III. BA BƯỚC THỰC HIỆN

Bước 1: PG cung cấp số (đã có gần hết)

  • 17 PG TRIGGER đếm realtime đã có (S116)
  • verify_counts() đã có
  • Cần: 1 PG FUNCTION trả 3 số tổng hợp:
    • Tổng thực thể (entities across all managed collections)
    • Tổng collection (managed collections count)
    • Tổng loài (species count)
  • Khi số thay đổi → PG NOTIFY (pub/sub có sẵn của PostgreSQL)

Bước 2: Ô gương soi trên Registries — Nuxt đọc thẳng PG

  • Nuxt endpoint riêng kết nối TRỰC TIẾP PG (pg driver, KHÔNG qua Directus)
  • Nhúng 1 ô nhỏ trên trang chủ Registries hiển thị 3 con số
  • Cập nhật tự động: PG NOTIFY → Nuxt lắng nghe (WebSocket/SSE hoặc polling ngắn 30s)
  • Code phải ĐƠN GIẢN NHẤT CÓ THỂ — ít code = ít lỗi = đáng tin

Tại sao không qua Directus? Vì đây là kênh kiểm chứng. Nếu Directus lỗi → kênh chính sai → gương soi vẫn đúng vì đọc thẳng PG. "Người kiểm tra không dùng chung dụng cụ với người bị kiểm tra."

Bước 3: Playwright trên VPS đọc số thật trên màn hình

Playwright chạy trên VPS (Docker container riêng hoặc cùng container) — KHÔNG phụ thuộc GitHub Actions. Lý do:

  • Chủ động 100%, không phụ thuộc chính sách bên thứ 3
  • Khởi động nhanh hơn (vài giây vs 30-60 giây của GitHub Actions)
  • Không tốn quota, không giới hạn số lần chạy
  • VPS đã có Docker, thêm Playwright image đơn giản

Cơ chế:

  1. PG số thay đổi → NOTIFY → đợi vài giây (để Nuxt render xong)
  2. Playwright trên VPS mở trình duyệt headless → vào Registries → đọc số hiển thị thật trên màn hình
  3. So sánh: Số PG = Số trên màn hình?
    • KHỚP → ô gương soi hiện màu xanh
    • LỆCH → ô gương soi hiện màu đỏ + cảnh báo + khởi động quy trình điều tra tự động

Dual-Trigger (Điều S131):

  1. Định kỳ: cron trên VPS (mỗi giờ hoặc tuỳ cấu hình)
  2. On-demand: gọi API bất kỳ lúc nào để verify ngay

GitHub Actions Playwright (đã có): Vẫn giữ làm lớp kiểm tra bổ sung khi CI/CD chạy. Nhưng không phải nguồn chính — VPS Playwright mới là nguồn chính.


IV. HIỂN THỊ TRÊN REGISTRIES

┌─────────────────────────────────────┐
│ 🪞 GƯƠNG SOI (PG trực tiếp)         │
│                                     │
│ Tổng thực thể:  9,847  ✅           │
│ Tổng collection:   18  ✅           │
│ Tổng loài:         21  ✅           │
│                                     │
│ Playwright verify: 2 phút trước ✅  │
│ (hoặc: ❌ LỆCH — xem chi tiết)     │
└─────────────────────────────────────┘
  • Số xanh = PG trực tiếp KHỚP với Playwright đọc trên màn hình
  • Số đỏ = LỆCH → tự cảnh báo, khởi động điều tra
  • Số trong ô này LUÔN là số PG trực tiếp — nếu kênh chính sai, ô này vẫn hiện số đúng

V. TẠI SAO ĐÁNG TIN

Rủi ro Kênh chính (qua Directus) Gương soi (PG trực tiếp + Playwright VPS)
Directus lỗi ❌ Sai ✅ Vẫn đúng (không dùng Directus)
Nuxt API code lỗi ❌ Sai ✅ Vẫn đúng (endpoint riêng, code đơn giản)
Nuxt Vue hiển thị lỗi ❌ Không biết ✅ Playwright đọc màn hình phát hiện
Điều 26 + 31 cùng sai ❌ Không biết ✅ Gương soi độc lập, phát hiện
GitHub thay đổi chính sách ❌ Mất verify ✅ Playwright trên VPS, không phụ thuộc
PG sai ❌ Cả hai cùng sai ❌ Cả hai cùng sai (PG sai = cực hiếm)

VI. KẾ HOẠCH THỰC HIỆN

Phase Việc Assembly First
31+ A PG function trả 3 số tổng hợp + NOTIFY PG FUNCTION — gần hết đã có
31+ B Nuxt endpoint đọc thẳng PG + ô gương soi nhúng trên Registries pg driver + 1 component đơn giản
31+ C Playwright Docker trên VPS + test case đọc số màn hình + so sánh PG Docker image + script đơn giản
31+ D Cơ chế cảnh báo: lệch → đỏ + auto-alert + khởi động điều tra PG NOTIFY + webhook/log

Nguyên tắc tối thượng: Code gương soi phải ĐƠN GIẢN. Gương soi phức tạp = gương soi cũng lỗi = vô nghĩa.


VII. PHÂN BIỆT VAI TRÒ

Thành phần Vai trò Chạy ở đâu
PG triggers + verify_counts() Nguồn sự thật, đếm realtime VPS (Docker PostgreSQL)
Điều 26 (Luật Đếm) Kiểm tra PG ↔ Nuxt API VPS (cron/on-demand)
Điều 31 (Toàn Vẹn) Phát hiện issues hệ thống VPS (runner cron/on-demand)
Điều 31+ Gương Soi Kiểm chứng độc lập: PG thẳng → Nuxt → Playwright đọc màn hình VPS (Playwright Docker)
GitHub Actions Playwright Lớp bổ sung khi CI/CD GitHub (giữ nhưng không phải nguồn chính)

Tất cả trên VPS = tự chủ 100%, không phụ thuộc bên ngoài.