Điều 28 — Phụ lục A: Nuxt/UI Assembly Governance (DRAFT)
Đ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 hardcodedtableIdMap→ vi phạm §0-AU + §1 - Tạo
/pages/notifications/index.vueriê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:
- 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.
- 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.
- 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ế.
- 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:
- Mỗi UI table PHẢI có
table_registryrecord vớitable_idduy nhất. - 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ộ). - Fields config từ registry, KHÔNG hardcode trong Nuxt component.
- 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_registryWHEREpage_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
- Public Access routes (
/knowledge/*) dùng anonymous/Public role, KHÔNG admin token. - Permission field allowlist PHẢI explicit — chỉ metadata fields.
- Unsafe fields blacklist (§4.4) áp dụng cho MỌI collection exposed qua Public Access.
- Write permissions (create/update/delete) KHÔNG cấp cho Public Access role trên data collections.
- 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ó:
- Lý do rõ ràng — tại sao PG/Directus/config/template không đủ?
- Approval từ user hoặc council
- Update Custom Code Registry (
knowledge/dev/ssot/custom-code-registry.md) - Rollback path documented
- 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_originhoặc tương đương
Áp dụng explicit cho:
- Tạo/sửa
table_registryrows - 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ó:
- Rollback ledger: Danh sách artifacts created/modified + exact IDs + action to undo
- Pre/post snapshot: Counts, states, permissions trước và sau
- Report: Upload KB, path chuẩn
dieu28-trien-khai/reports/ - Review: GPT hoặc Opus review trước khi close pack
§12. Security boundaries
- Không expose: secrets, raw payload, vector, embedding, token, password, SSN, personal data
- SSR fetch dùng Public role, KHÔNG admin token
- Client fetch dùng user session (authenticated) hoặc Public role (anonymous)
- Admin token KHÔNG BAO GIỜ xuất hiện trong Nuxt runtime code
- 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