KB-356E

Điều 28 — Phụ lục A: Nuxt/UI Assembly Governance (DRAFT)

10 min read Revision 1
dieu28appendixnuxtuigovernancedraft2026-05-08

ĐIỀU 28 — PHỤ LỤC A: LUẬT VẬN HÀNH NUXT / UI ASSEMBLY / HIỂN THỊ

DRAFT v0.1 | 2026-05-08 | Opus soạn, chờ GPT/User review Cấp: Phụ lục chính thức Điều 28 — Luật Kỹ Thuật Hiển Thị v2.0 Phạm vi: Mọi file trong web/ directory và mọi quyết định liên quan Nuxt/UI/display/template Không thay thế: Điều 28 chính. Phụ lục này BỔ SUNG operational detail cho Điều 28.


§0. Quan hệ với luật hiện hành

Luật Vai trò Quan hệ
Điều 7 Assembly First / thứ tự ưu tiên Luật mẹ — PG → Directus → Nuxt → open source → code mới
Điều 28 chính Luật nguyên tắc hiển thị / khuôn mẫu Phụ lục này triển khai operational detail
Điều 41 VPS = SSOT cho code Nuxt code phải trên VPS, deploy qua GH→SSH
Điều 43 Context/graphic outputs Nuxt render context pack data, không duplicate logic
NT12 DOT cặp (chính + phụ) Mọi DOT thay đổi UI phải có DOT kiểm tra tương ứng
NT13 PG First Muốn giải pháp ngoài PG phải xin phép + giải thích
§0-AU Cấm hardcode Route maps, entity maps, collection maps cấm hardcode

Nguyên tắc thẩm quyền: Mọi vấn đề liên quan hiển thị/khuôn mẫu/UI/template thuộc Điều 28. Nếu phát sinh gap, bổ sung phụ lục Điều 28 — KHÔNG tạo luật mới chồng lấn.


§1. Cấm UI bespoke / Cấm workaround cục bộ

Nguyên tắc 1: UI phải sinh từ schema/config/template. Mỗi instance mới = khai báo config, KHÔNG code mới.

Nguyên tắc 2: Nếu shared module/template thiếu capability → DỪNG, sửa shared module — KHÔNG workaround cục bộ cho 1 collection/feature cụ thể.

Nguyên tắc 3: Nếu module cũ không đáp ứng → dừng, amend phụ lục + repair shared module. Không tạo double system.

Test: Nếu thêm 1 bảng/trang/component mới mà phải sửa code Nuxt (ngoài config/registry) → vi phạm. Phải quay lại sửa shared mechanism trước.

Ví dụ vi phạm:

  • Thêm event_outbox: 'tbl_event_outbox' vào hardcoded tableIdMap → vi phạm §0-AU + §1
  • Tạo /pages/notifications/index.vue riêng cho notification → vi phạm §1 nguyên tắc 1
  • Copy DirectusTable code rồi sửa cho 1 collection → vi phạm Điều 28 nguyên tắc 2 (SSOT)

§2. Template / Khuôn lifecycle

Kế thừa nguyên văn Điều 28 chính §III (Nguyên tắc 3):

draft → active → deprecated → retired

Bổ sung operational rules:

  1. draft: Template mới được thiết kế, chưa có instance production. Có thể thay đổi config schema. Phải có ít nhất 1 test instance.
  2. active: Template có instance production. Thay đổi config schema phải backward compatible. Sửa template = tất cả instances tự cập nhật.
  3. deprecated: Template có thay thế tốt hơn. Instances hiện có vẫn hoạt động nhưng không tạo instance mới. Phải có migration path sang template thay thế.
  4. retired: Template xóa khỏi codebase. Mọi instance đã migrate. Birth record vẫn còn (lịch sử).

Gate: Chuyển trạng thái template PHẢI qua council review, KHÔNG tự ý.


§3. Product-from-template registry

Mỗi UI product PHẢI point to template + config source.

Thuộc tính bắt buộc Ví dụ
Product ID tbl_event_outbox
Template TPL-001 (DirectusTable)
Config source table_registry.fields WHERE table_id='tbl_event_outbox'
Status draft / published / archived
Page URL /knowledge/registries/event_outbox

Không có registry record = UI product KHÔNG ĐƯỢC PHÉP tồn tại. (Kế thừa Table Module SSOT §I rule 1.)

Reconciliation requirement: Số lượng registry records phải khớp giữa:

  • Live Directus collection (ví dụ: table_registry)
  • KB synced docs (ví dụ: registries/table_registry/tbl_*)
  • Active UI routes

Sai lệch = gap cần điều tra, KHÔNG bỏ qua.


§4. Table Module / DirectusTable obligations

Promote từ Table Module SSOT lên law-level:

  1. Mỗi UI table PHẢI có table_registry record với table_id duy nhất.
  2. DirectusTable = cổng duy nhất render bảng. Cấm <UTable> trực tiếp, cấm custom <table> HTML (trừ DirectusTable.vue nội bộ).
  3. Fields config từ registry, KHÔNG hardcode trong Nuxt component.
  4. Permission + field allowlist interaction:
    • Directus permission allowlist (14+ metadata fields) ⊇ registry fields config
    • Registry fields config ⊆ permission allowlist
    • Unsafe fields (safe_payload, correlation_id, causation_id, payload, body, raw_payload, vector, embedding, secret, token, password, ssn, personal_data) PHẢI absent từ CẢ HAI permission và registry config.

§5. Route resolution — CẤM hardcode maps

Đây là gap critical nhất hiện tại.

Hiện trạng vi phạm: web/pages/knowledge/registries/[entityType]/index.vue line ~39 chứa hardcoded tableIdMap — mỗi collection mới cần sửa code.

Yêu cầu luật:

  • Route resolution PHẢI registry/config-driven
  • Cấm hardcoded entity→tableId maps trong Nuxt code
  • Mechanism cụ thể do design plan quyết định (xem Phụ lục thiết kế)

Candidate mechanisms (law không chọn, design chọn):

  • A. Runtime query table_registry WHERE page_url = current path
  • B. Runtime query WHERE collection = entityType parameter
  • C. Build-time generated map từ registry (acceptable nếu auto-generated, KHÔNG manual)

Migration plan: Sau khi design được duyệt, thay thế toàn bộ hardcoded maps bằng shared mechanism. Tất cả registry-backed tables tự động render mà KHÔNG cần code change.


§6. Directus permission and field allowlist

  1. Public Access routes (/knowledge/*) dùng anonymous/Public role, KHÔNG admin token.
  2. Permission field allowlist PHẢI explicit — chỉ metadata fields.
  3. Unsafe fields blacklist (§4.4) áp dụng cho MỌI collection exposed qua Public Access.
  4. Write permissions (create/update/delete) KHÔNG cấp cho Public Access role trên data collections.
  5. Mỗi permission mới PHẢI ghi ID + pack origin vào rollback ledger.

§7. Nuxt code authorization gate

Thay đổi code Nuxt PHẢI có:

  1. Lý do rõ ràng — tại sao PG/Directus/config/template không đủ?
  2. Approval từ user hoặc council
  3. Update Custom Code Registry (knowledge/dev/ssot/custom-code-registry.md)
  4. Rollback path documented
  5. Smoke verification (máy hoặc tay — nhưng tay = gap cần sửa)

Mọi file Nuxt mới hoặc sửa PHẢI đăng ký. Không đăng ký = invisible = vi phạm §0-AY (không register = vô hình).


§8. Legacy cleanup taxonomy

Mỗi file/component/pattern legacy trong web/ PHẢI phân loại:

Phân loại Ý nghĩa Hành động
KEEP Code đang dùng, chưa có thay thế, phù hợp kiến trúc Giữ nguyên, đăng ký
MIGRATE Code đang dùng nhưng có template/shared thay thế Lên lịch migrate, ghi deadline
QUARANTINE Code có vấn đề nhưng chứa data/logic cần giữ tạm Đánh dấu, cách ly, ghi lý do giữ
DELETE Code không dùng, không data, không dependency Xóa clean, ghi rollback
UNKNOWN Chưa phân loại Agent cần điều tra trước khi phân loại

Gate: Không ai được xóa code mà chưa phân loại. Không ai được giữ code UNKNOWN quá 2 sprint.


§9. Automated verification gates

Nguyên tắc: Những gì máy móc làm được thì không dùng con người.

Gate Kiểm tra gì Manual OK?
Route smoke HTTP status + page renders Chỉ tạm thời — phải tự động hóa
Component mount smoke SharedDirectusTable mounted + fields fetched Chỉ tạm thời
Field leak smoke Unsafe fields absent from response Chỉ tạm thời
Registry compliance tableId in code ↔ table_registry rows Phải tự động (CI)
Custom code audit Mỗi .vue/.ts file registered Phải tự động (CI)

Manual smoke = gap to repair, KHÔNG phải final architecture. Nếu smoke chưa tự động → ghi technical debt, fix trong sprint tiếp.


§10. DOT/API-only mutation

Kế thừa DOT 100% rule:

  • KHÔNG click Directus UI để config
  • Mọi thay đổi collection/permission/field/registry qua DOT tool hoặc API script
  • Evidence phải ghi _dot_origin hoặc tương đương

Áp dụng explicit cho:

  • Tạo/sửa table_registry rows
  • Tạo/sửa Directus permissions
  • Tạo/sửa field metadata/translations
  • Publish/unpublish registry entries

§11. Rollback and report

Mỗi pack thay đổi Nuxt/UI PHẢI có:

  1. Rollback ledger: Danh sách artifacts created/modified + exact IDs + action to undo
  2. Pre/post snapshot: Counts, states, permissions trước và sau
  3. Report: Upload KB, path chuẩn dieu28-trien-khai/reports/
  4. Review: GPT hoặc Opus review trước khi close pack

§12. Security boundaries

  1. Không expose: secrets, raw payload, vector, embedding, token, password, SSN, personal data
  2. SSR fetch dùng Public role, KHÔNG admin token
  3. Client fetch dùng user session (authenticated) hoặc Public role (anonymous)
  4. Admin token KHÔNG BAO GIỜ xuất hiện trong Nuxt runtime code
  5. Field allowlist là defensive layer — ngay cả khi Nuxt code bị sai, Directus permission vẫn chặn unsafe fields

§13. Compatibility với Điều 43

  • Nuxt render context pack data từ Directus/PG projection
  • KHÔNG duplicate business logic đã có trong PG
  • KHÔNG fetch raw data rồi tính toán trên Nuxt — nếu cần tính toán → PG view/function → Directus expose → Nuxt render
  • Context/graphic outputs (Điều 43) = PG source → Directus projection → Nuxt display

§14. Phụ lục con / Thiết kế / Triển khai

Phụ lục A này là luật vận hành. Các tài liệu thiết kế và triển khai cụ thể nằm ở:

Tài liệu Path Loại
Chỉ mục thiết kế/triển khai dieu28-trien-khai/appendices/d28-ui-template-design-implementation-index.md Living index
Design plan dieu28-trien-khai/design/d28-nuxt-ui-template-consolidation-design-plan.md Design
Agent verification prompt dieu28-trien-khai/prompts/d28-nuxt-ui-template-live-inventory-verification-prompt.md Prompt
Agent verification report dieu28-trien-khai/reports/d28-nuxt-ui-template-live-inventory-verification-report.md Report (chưa tạo)

Điều 28 Phụ lục A v0.1 DRAFT | 2026-05-08 | Chờ GPT/User review

Back to Knowledge Hub knowledge/dev/laws/dieu28-trien-khai/appendices/d28-nuxt-ui-assembly-governance-appendix-draft.md