D28 — Nuxt/UI/Template Consolidation Design Plan (DRAFT)
D28 — Nuxt/UI/Template Consolidation Design Plan
DRAFT v0.2 | 2026-05-08 | Updated with Agent evidence + GPT route-resolution correction Phụ thuộc: Phụ lục Điều 28 approved + VPS reverify trước implementation Scope: Thiết kế, KHÔNG implementation.
0. Ngữ cảnh
Notification Phase 1 (P3D) đạt 90% nhưng blocked bởi Nuxt hardcoded maps. User/GPT quyết định dừng, viết luật (Điều 28 phụ lục), rồi sửa mechanism chung.
Agent live inventory (2026-05-08) cung cấp evidence cụ thể. Design plan v0.2 cập nhật dựa trên data thực.
1. Thay thế hardcoded maps bằng registry-driven resolution
1.1 Vấn đề — 3 điểm hardcoded (CONFIRMED_ISSUE)
| File | Map | Entries | Source |
|---|---|---|---|
pages/knowledge/registries/[entityType]/index.vue:39-58 |
tableIdMap | 18 | LOCAL_FACT |
config/detail-sections.ts:227 |
collectionMap | ? | LOCAL_FACT |
server/api/discovery/relations.get.ts:19 |
collectionMap mirror | ? | LOCAL_FACT |
Tất cả 3 map phải migrate cùng lúc (hoặc ít nhất cùng design).
1.2 Evidence từ Agent — route convention analysis
total_live_rows=21
collection_equals_entityType=1/21 (chỉ event_outbox)
page_url_convention_match=13/21
exception_rows=8/21 (workflow tabs, modules, tasks, proposals, registries index)
Kết luận: entityType ↔ collection KHÔNG consistent vì collection plural, entityType singular. Bất kỳ runtime lookup nào dựa trên collection = entityType sẽ fail 18/21 rows.
1.3 Options — updated assessment
Option B — Runtime query by collection → REJECTED as primary
collection_match_rate=1/21 (4.8%)
Fail cho 20/21 rows. Không khả thi kể cả với convention mapping (plural↔singular).
Option A — Runtime query by page_url → PARTIAL candidate
page_url_convention_match=13/21 (62%)
exception_rate=8/21 (38%)
13/21 rows match /knowledge/registries/{entityType}. 8 rows có non-standard page_url (workflow tabs ?tab=, /admin/, /knowledge/modules, /knowledge/current-tasks, /knowledge/registries index). Cần fallback cho 38% exceptions.
Ưu: Không cần convention mapping. URL = source of truth. Nhược: 38% exception rate cao. Extra runtime API call. page_url substring matching fragile.
Option C — Build-time generated map → PRIMARY CANDIDATE ✅
Ý tưởng: DOT/script query table_registry → generate static map file → Nuxt import
Khi nào generate: build time (nuxt build) hoặc deploy hook
BUILD STEP:
curl GET /items/table_registry?fields=id,table_id,collection,page_url,status
→ transform to: { entityType: table_id } map
→ write to web/generated/tableIdMap.ts (auto-generated, NOT manual)
NUXT:
import { tableIdMap } from '~/generated/tableIdMap'
// Replaces hardcoded map — same usage, different source
Ưu:
- Zero runtime cost (static import)
- Deterministic — map = exact registry state at build time
- Auto-generated = NOT hardcode (§0-AU compliant)
- Convention mapping handled by generation script (entityType ↔ table_id ↔ collection)
- 100% coverage — every table_registry row gets an entry
Nhược:
- Cần rebuild/redeploy khi thêm table mới → acceptable (thêm table = cần deploy anyway)
- Generation script cần maintain → simple script, low burden
Quan trọng: Manual edit of generated file = vi phạm. File PHẢI có header:
// AUTO-GENERATED from table_registry — DO NOT EDIT MANUALLY
// Generated by: scripts/generate-table-maps.ts
// Source: GET /items/table_registry
// Date: ${ISO_DATE}
Option D — Hybrid (build-time + runtime fallback) → FALLBACK CANDIDATE
Build step: generate static map (same as C)
Runtime: if entityType not in static map → query table_registry live → cache
Ưu: Handles new tables added between deploys. Nhược: Complexity. Cần runtime Directus read permission cho table_registry on Public Access role.
1.4 Recommendation v0.2
PRIMARY: Option C (build-time generated map)
FALLBACK: Option D (hybrid) — chỉ nếu C không đáp ứng
REJECTED: Option B (collection lookup)
PARTIAL: Option A (page_url) — có thể dùng trong generation script
Yêu cầu bắt buộc:
- Generated map PHẢI sinh từ table_registry bằng DOT/API/script
- KHÔNG edit tay file generated
- Generation script = registered tool, có DOT cặp (Cấp B generate + Cấp A verify)
- Trước implementation PHẢI VPS reverify (Nuxt findings hiện = LOCAL_FACT)
1.5 Generation script scope (sơ bộ — detail khi implement)
Script cần generate 3 maps từ table_registry:
| Map | Thay thế | Dùng ở đâu |
|---|---|---|
| tableIdMap | [entityType]/index.vue:39 |
Registry route resolution |
| collectionMap | detail-sections.ts:227 |
Entity→collection mapping |
| reverseCollectionMap | detail-sections.ts:252 |
Collection→entity reverse |
Có thể 1 script sinh 1 file chứa cả 3 maps. hoặc 3 files riêng. Design khi implement.
1.6 collectionMap mirror (relations.get.ts)
Server API server/api/discovery/relations.get.ts:19 mirror collectionMap. Phải consume from same generated source. KHÔNG maintain 2 copies.
2. Automated route smoke design — unchanged from v0.1
(Phase 1 bash curl, Phase 2 Playwright, Phase 3 CI. Detail giữ nguyên.)
3. Template registry reconciliation — unchanged from v0.1
4. Legacy cleanup phases — updated
Phase L0 — VPS reverify (NEW — required before L1)
Agent chạy grep trên VPS /opt/incomex cho Bước 2-4 của inventory prompt. Confirm/update LOCAL_FACT findings.
Phase L1 — Generate maps (Option C implementation)
- Write generation script
- Generate 3 maps from table_registry
- Replace hardcoded maps with generated imports
- Verify all registry routes resolve correctly
- Route smoke
Phase L2 — Resume P3D
- Generated map includes event_outbox → tbl_event_outbox
- Route smoke:
/knowledge/registries/event_outbox→ SharedDirectusTable mounts - Field leak smoke: unsafe fields 403
- Publish tbl_event_outbox: draft → published
- P3D Phase 1 = COMPLETE
Phase L3 — Migrate UTable direct usages (11 knowledge/admin)
Per Agent 4B findings.
Phase L4 — Migrate business calcs (6 pages)
Per Agent 4F findings. Move to PG views → Directus → render.
Phase L5 — Cleanup remaining
HTML table MatrixView, portal UTable review, stale docs.
5. Cách resume P3D tbl_event_outbox — updated
Preconditions (updated)
- ✅ Phụ lục Điều 28 approved (or enacted)
- ✅ Design plan v0.2+ approved
- ✅ VPS reverify complete (Phase L0)
- ✅ Generation script built + maps generated (Phase L1)
- ✅ Route smoke pass for event_outbox
Steps — same as v0.1 (R1-R5)
Nhưng R1 bây giờ = "generated map deployed" thay vì "dynamic lookup deployed".
6. Open decisions (updated)
| # | Decision | Status | Notes |
|---|---|---|---|
| 1 | Route resolution mechanism | Option C primary | GPT approved direction. Final confirm after VPS reverify |
| 2 | Template registry location | Deferred | KB docs sufficient for now |
| 3 | Smoke Phase 1 tool | bash + curl | |
| 4 | Legacy cleanup priority | L0→L1→L2→L3→L4→L5 | |
| 5 | Table Module SSOT update | After implementation | |
| 6 | Generation script design | Deferred to implementation | 1 script, 3 maps, DOT cặp |
| 7 | collectionMap server mirror | Consume from generated source |
D28 Design Plan | v0.2 | Option C primary, Option B rejected | Agent evidence merged | 2026-05-08