Files
DashBoard/openspec/changes/archive/2026-02-09-migrate-tables-vue/design.md
egg dcbf6dcf1f feat(tables): migrate /tables page from Jinja2 to Vue 3 + Vite
Rewrite 237-line vanilla JS + Jinja2 template into Vue 3 SFC components
(App.vue, TableCatalog.vue, DataViewer.vue, useTableData composable).
Establishes apiPost POST request pattern for pure Vite pages. Removes
templates/index.html, updates Vite entry to HTML, and Flask route to
send_from_directory. Includes sql_fragments WHERE_CLAUSE escaping fix,
updated integration tests, and OpenSpec artifact archive.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 14:52:14 +08:00

3.8 KiB
Raw Blame History

Context

Tables 頁面(/tables)是開發者工具頁面,允許瀏覽 19 張 DWH 表的欄位與內容。目前架構:

  • Jinja2 模板 index.html extends _base.htmlserver-render TABLES_CONFIG 為表格卡片
  • vanilla JS (237 行) 用 DOM 操作管理狀態,透過 window.MesApi.post() 呼叫 API
  • 兩個 POST API/api/get_table_columns/api/query_table;一個 GET API/api/get_table_info

QC-GATE 遷移已建立 Vue 3 + Vite 純前端架構模式GET-only本次需補齊 POST 請求模式。

Goals / Non-Goals

Goals:

  • 將 Tables 頁面完整遷移為 Vue 3 SFC複用 QC-GATE 架構模式
  • 建立 POST 請求在純 Vite 頁面中的標準做法(apiPost from core/api.js
  • 表格配置改由前端 apiGet('/api/get_table_info') 動態取得,脫離 Jinja2 context
  • 遷移完成後移除 Jinja2 模板 templates/index.html

Non-Goals:

  • 不修改後端 API 邏輯或 SQL 查詢(保持現有 /api/query_table/api/get_table_columns 不變)
  • 不改變 CSRF 策略(現有 CSRF 僅 enforce /admin/* 路徑Tables API 不受影響)
  • 不增加新功能(如分頁、排序、匯出),僅 1:1 功能遷移
  • 不建立共用 Vue 元件庫(本次僅 Tables 頁面內部元件化)

Decisions

D1: CSRF token 不需額外處理

選擇Tables 的 POST API 不需 CSRF token 理由csrf.pyshould_enforce_csrf() 僅對 /admin/* 路徑啟用 CSRF。/api/query_table/api/get_table_columns 不在 enforce 範圍內。apiPost() 已內建 CSRF header 邏輯(從 <meta> 讀取),即使沒有 meta tag 也只是發送空字串,不會失敗。 替代方案:新增 CSRF token API endpoint — 不需要,因為 Tables API 本身就不 enforce。

D2: 表格配置從 API 動態取得

選擇:前端在 mount 時呼叫 GET /api/get_table_info 取得 TABLES_CONFIG 理由:該 endpoint 已存在(app.py:453),直接返回 TABLES_CONFIG dict。無需建立新 API。 替代方案:將 config 打包成靜態 JSON — 不適合config 含 row_count 等可能更新的資訊。

D3: Vite entry 改為 HTML entry point

選擇vite.config.js 中 tables entry 從 src/tables/main.js 改為 src/tables/index.html 理由:與 QC-GATE 模式一致HTML entry 讓 Vite 處理完整的 HTML → JS → CSS pipeline。 影響npm run build 會輸出 tables.htmltables.jstables.cssstatic/dist/

D4: 元件拆分策略

選擇3 個 Vue 元件 + 1 個 composable

  • App.vue — 根佈局,管理 loading/error 狀態
  • TableCatalog.vue — 表格卡片目錄(分類顯示)
  • DataViewer.vue — 資料檢視器(欄位篩選 + 查詢結果表格)
  • useTableData.js — composable 封裝 API 呼叫和狀態管理

理由:對應原始 UI 的兩個主要區塊(表格選擇 / 資料檢視),職責清晰。

D5: 現有 vanilla JS main.js 直接替換

選擇:將現有 frontend/src/tables/main.js (237 行) 替換為 Vue 3 bootstrap 入口(~7 行),原始邏輯分散至 Vue 元件和 composable 中。 理由vanilla JS 全部是 DOM 操作,無法漸進式遷移,需整體重寫。

Risks / Trade-offs

  • [風險] 大表警示標記遺失Jinja2 模板中有 {% if table.row_count > 10000000 %} 顯示「大表」badge。 → 遷移:在 TableCatalog.vue 中用 Vue 條件渲染實現相同邏輯。

  • [風險] Fallback inline script 移除index.html 含 ~200 行 fallback JSVite build 不存在時)。 → 接受Vite build 是 deployment 的標準流程fallback 不再需要。

  • [風險] CSS 樣式差異:原始 ~335 行 embedded CSS 需遷移至 style.css。 → 遷移:提取核心樣式至獨立 CSS 檔案,與 QC-GATE 風格統一。