P10B-2C-R2-FOLLOWUP d28-render-raw.tsv
canonical_address|depth|section_type|title|body D38-DIEU28-ROOT|0|heading|ĐIỀU 28: LUẬT KỸ THUẬT HIỂN THỊ — v2.0 BAN HÀNH| D38-DIEU28-S0|1|paragraph|Preamble|> v2.0 BAN HÀNH | S150 (2026-04-01) | Huyên đề xuất + Claude soạn
Đổi tên: "Luật Khuôn Mẫu Chuẩn" → "LUẬT KỸ THUẬT HIỂN THỊ" Kế thừa: v1.0 (S157). Mở rộng: +Collection PG, +Nuxt whitelist, +Checklist, +Quy trình test, +Chuyển giao, +Coverage scanner. Hội đồng: GPT 8.4/10 + Gemini 9.5/10. 2 vòng review. Đồng thuận ban hành. Rà soát: 13/13 NT — 0 vi phạm (S165-KB rà soát). D38-DIEU28-S1|1|heading|I. TUYÊN BỐ CỐT LÕI| D38-DIEU28-S1-P1|2|paragraph|I. TUYÊN BỐ CỐT LÕI (intro)|> Nuxt CHỈ render từ khuôn đã đăng ký trong PG. Không có khuôn = không có giao diện. Không có ngoại lệ.
Mọi giao diện hiển thị business data trong Incomex = 1 instance của 1 khuôn mẫu chuẩn (template). Khuôn được code 1 LẦN, đăng ký trong PG, kiểm soát bởi DOT. Instance = config data trong PG → khuôn render. Thêm giao diện mới = INSERT config, KHÔNG code. D38-DIEU28-S1-P2|2|paragraph|Phạm vi luật — 3 lớp rõ ràng|| Lớp | Ví dụ | Thuộc Điều 28? | |-----|-------|---------------| | Display template | DirectusTable, DirectusMatrix, TabPivot, DynamicEntityList | ✅ CÓ — phải đăng ký | | Hạ tầng UI | Layout shell, NavBar, ErrorPage, LoadingSpinner | ❌ KHÔNG — hạ tầng cố định | | PG trigger/function | BirthTrigger, pivot_matrix() | ❌ KHÔNG — backend |
D38-DIEU28-S2|1|heading|II. 5 NGUYÊN TẮC| D38-DIEU28-S2-P1|2|principle|NT-D1: NUXT = MÀN HÌNH, CHỈ RENDER TỪ KHUÔN|Nuxt ĐƯỢC: đọc Directus API, render từ khuôn, phát event/submit payload. Nuxt KHÔNG ĐƯỢC: business logic, query DB, tạo component ngoài khuôn, hardcode, điều phối logic submit. D38-DIEU28-S2-P2|2|principle|NT-D2: KHUÔN = SSOT, CODE 1 LẦN|1 loại giao diện = 1 khuôn. Instance = config. Sửa khuôn = tất cả instances cập nhật. D38-DIEU28-S2-P3|2|principle|NT-D3: CONFIG TRONG PG, KHÔNG TRONG TEXT|Config trong PG (JSONB) để validate, query, DOT thao tác. Text = documentation. D38-DIEU28-S2-P4|2|principle|NT-D4: KHUÔN LÀ THỰC THỂ QUẢN TRỊ|Đăng ký design_templates, birth record, species SPE-TPL, DOT-health, PASS test. D38-DIEU28-S2-P5|2|checklist|NT-D5: MÁY ĐÚC KHUÔN — CHECKLIST 8 BỘ PHẬN|| # | Bộ phận | Quên thì sao | |---|---------|-------------| | 1 | config_schema (JSONB) | Lỗi âm thầm | | 2 | PG validation (CHECK) | INSERT bậy | | 3 | Error boundary | Trang trắng | | 4 | Loading + Empty state | UI treo | | 5 | DOT-health | Lỗi không ai biết | | 6 | Test 5/5 PASS | Khuôn lỗi lan | | 7 | Documentation | Không dùng được | | 8 | Birth record (auto) | Không biết tồn tại |
Thiếu 1 = KHÔNG active. PG trigger enforce (§III).
D38-DIEU28-S3|1|heading|III. COLLECTION design_templates|
D38-DIEU28-S3-P1|2|technical_spec|Schema|| Field | Kiểu | Constraint | Mục đích |
|-------|------|-----------|----------|
| id | SERIAL | PK | |
| code | TEXT | UNIQUE NOT NULL | TPL-xxx |
| name | TEXT | NOT NULL | Tên hiển thị |
| description | TEXT | nullable | Mô tả + cách dùng |
| version | INT | DEFAULT 1 | Version hiện tại |
| config_schema | JSONB | NOT NULL | Quy tắc validate config |
| component_path | TEXT | nullable | Nuxt component |
| instance_collection | TEXT | FK → collection_registry.collection_name | Collection chứa instances — FK enforce |
| instance_count | INT | DEFAULT 0 | AUTO cập nhật bởi PG trigger |
| checklist_status | JSONB | DEFAULT '{}' | 8 bộ phận — DOT validate đủ 8 key |
| test_results | JSONB | DEFAULT '{}' | 5 loại test — DOT verify |
| migration_source | TEXT | nullable | Component gốc (chuyển giao) |
| status | TEXT | FK → template_statuses.code, DEFAULT 'draft' | Lifecycle — FK enforce |
| species_code | TEXT | DEFAULT 'template' | SPE-TPL |
| composition_level | TEXT | DEFAULT 'material' | Lớp 4 |
D38-DIEU28-S3-P2|2|technical_spec|★ REFERENCE TABLE cho status (NT4+NT10)|```sql
CREATE TABLE template_statuses (code TEXT PRIMARY KEY, name TEXT NOT NULL, sort_order INT);
INSERT INTO template_statuses VALUES
('draft', 'Nháp', 1),
('testing', 'Đang test', 2),
('active', 'Hoạt động', 3),
('deprecated', 'Lỗi thời', 4),
('retired', 'Ngừng', 5);
ALTER TABLE design_templates ADD CONSTRAINT fk_tpl_status FOREIGN KEY (status) REFERENCES template_statuses(code);
Thêm trạng thái mới = INSERT 1 row. KHÔNG ALTER TABLE.
D38-DIEU28-S3-P3|2|technical_spec|★ PG TRIGGER enforce lifecycle (Tuyên ngôn ②)|```sql
CREATE FUNCTION fn_template_lifecycle_guard() RETURNS TRIGGER AS $$
BEGIN
-- CẤM nhảy cóc: draft→active (bỏ qua testing)
IF OLD.status = 'draft' AND NEW.status = 'active' THEN
RAISE EXCEPTION 'CẤM draft→active. PHẢI qua testing (5/5 PASS).';
END IF;
-- CẤM active khi checklist chưa đủ 8 bộ phận
IF NEW.status = 'active' AND (
SELECT COUNT(*) FROM jsonb_object_keys(NEW.checklist_status)
) < 8 THEN
RAISE EXCEPTION 'CẤM active khi checklist < 8. Hiện: %',
(SELECT COUNT(*) FROM jsonb_object_keys(NEW.checklist_status));
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_template_lifecycle
BEFORE UPDATE ON design_templates
FOR EACH ROW WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION fn_template_lifecycle_guard();
→ Agent KHÔNG THỂ active khuôn chưa test hoặc checklist thiếu. D38-DIEU28-S3-P4|2|governance_process|Quy tắc versioning|- Không breaking: KHÔNG tăng version. Instance tự hưởng.
- Breaking: TĂNG version. Backward compatibility nội bộ.
- CẤM: Sửa breaking mà không tăng version.
D38-DIEU28-S3-P5|2|governance_process|Quy tắc instance|- Instance PHẢI có
template_code(FK) +template_version(INT). - Khuôn upgrade → instances cũ giữ version cũ → render theo version đó.
D38-DIEU28-S4|1|process|IV. QUY TRÌNH TEST KHUÔN — 5/5 PASS = ACTIVE|| Test | Tên | Tiêu chí PASS | |------|-----|--------------| | 1 | Validation Gate | 5/5 config sai bị reject | | 2 | Multi-Instance | 3/3 configs render đúng, Nuxt = PG | | 3 | Resilience | 5/5 edge cases không crash | | 4 | Truth Check | 100% ô Nuxt = PG, 0 sai | | 5 | Live Config | Sửa config → giao diện đổi ngay, không deploy |
Lifecycle: draft → testing (5/5 PASS) → active. PG trigger enforce (§III).
D38-DIEU28-S5|1|technical_spec|V. DOT QUẢN TRỊ — PAIRED (NT12)|| DOT | Cấp | Chức năng | Paired với | Trigger | |-----|-----|----------|-----------|---------| | DOT-template-create | B | Tạo + đăng ký khuôn mới | DOT-template-health | on-demand | | DOT-template-health | A | Kiểm tra checklist, test re-run, coverage | — (self-monitoring) | cron (đọc từ dot_config) + manual | | DOT-template-coverage | A | Quét route/component ngoài registry | — | cron weekly + manual |
Dual-trigger (NT7): Cron (đọc schedule từ dot_config) + on-demand manual.
D38-DIEU28-S6|1|process|VI. QUY TRÌNH TẠO KHUÔN MỚI|1. Kiểm tra khuôn phù hợp đã có? → CÓ → INSERT config. XONG. 2. Thiết kế (4 bước HP) → 3. Đăng ký (DOT-template-create, status='draft') → 4. Implement (code 1 lần) → 5. Test (5/5) → 6. UPDATE status='testing' → 7. UPDATE status='active' → PG trigger verify checklist 8/8.
D38-DIEU28-S7|1|process|VII. CHUYỂN GIAO COMPONENT HIỆN CÓ|### 4 CÓ = đưa vào: Tái sử dụng + Config-driven + Độc lập + Ổn định.
KHÔNG đưa vào: Hạ tầng UI, backend, dùng 1 lần, chưa ổn định.
Quy trình: Kiểm kê → Đăng ký (draft) → Bổ sung thiếu → Test 5/5 → Activate.
| Component | Ứng viên |
|---|---|
| DynamicEntityList/Detail | ✅ TPL-DYNAMIC-LIST/DETAIL |
| TabPivotView | ✅ TPL-TAB-PIVOT |
| CommentModule | ✅ TPL-003 |
| WorkflowModule | ✅ TPL-004 |
| TaskModule | ✅ TPL-005 |
| InspectorDOT | 🔄 TPL-006 |
| Layout/NavBar/Error | ❌ Hạ tầng |
| BirthTrigger | ❌ Backend |
D38-DIEU28-S8|1|heading|VIII. NUXT WHITELIST + COVERAGE SCANNER| D38-DIEU28-S8-P1|2|technical_spec|Whitelist|Nuxt load → đọc template_code → SELECT design_templates WHERE status='active' → CÓ → render / KHÔNG → "Not found". D38-DIEU28-S8-P2|2|technical_spec|Coverage Scanner (DOT-template-coverage)|3 câu: (1) Route nào do template nào render? (2) Route ngoài registry? (3) Component ngoài whitelist? Mục tiêu: 0 ngoài registry = coverage 100%.
D38-DIEU28-S9|1|paragraph|IX. QUAN HỆ VỚI LUẬT KHÁC|| Luật | Quan hệ | |------|---------| | Điều 0-G | Khuôn → birth_registry auto | | NT1 (SSOT) | design_templates = SSOT | | NT4 (Sẵn sàng) | Instance = config, ref table status | | NT10 (PG quản lý) | Config PG, status FK, lifecycle trigger | | NT12 (DOT cặp) | create(B)↔health(A) | | NT13 (Ưu tiên PG) | PG trigger lifecycle guard | | Điều 35 (DOT) | DOT lifecycle, dùng chung dot_config | | Điều 36 (Collection) | instance_collection FK, template_code FK enforce |
D38-DIEU28-S10|1|checklist|X. NỢ KỸ THUẬT|| TD | Nội dung | Khi nào | |----|---------|--------| | TD-A | CI scanner cấm import ngoài whitelist | Sau ban hành | | TD-B | Runtime manifest từ PG | Sau ban hành | | TD-C | Permissions/scope per template | Multi-role | | TD-D | Performance budget | TPL-002 active | | TD-E | Tách _tests, _health tables | >50 khuôn | | TD-F | Semver, compatibility matrix | Khuôn upgrade | D38-DIEU28-S11|1|paragraph|Footer|Điều 28 v2.0 BAN HÀNH | 13/13 NT ✅ | 6/6 Q ✅ | Ref table status | PG trigger lifecycle+checklist guard | DOT paired rõ | instance_collection FK | Dùng chung dot_config (27 rows)