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

64 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Context
Tables 頁面(`/tables`)是開發者工具頁面,允許瀏覽 19 張 DWH 表的欄位與內容。目前架構:
- Jinja2 模板 `index.html` extends `_base.html`server-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.py``should_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.html``tables.js``tables.css``static/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 風格統一。