# LLM 開發操作指南 ## 文件目的 本專案是給其他 Vue/Vuetify 專案使用的 template。LLM 協助修改時,預設應在 `src` 底下依分層規則新增或修改頁面、元件、store、service 與 composable。 本文件只保留全域操作順序與導覽。各層細節規範放在 `src/**/GUIDE.md`,避免重複維護。 ## 建議閱讀順序 1. `src/GUIDE.md` 2. `docs/architecture-strategy.md` 3. 依 `maintenanceContract.pageKind` 閱讀對應的 demo 與 `src/**/GUIDE.md`(查 `docs/architecture-strategy.md` 的分層說明) 4. `docs/add-page-example.md`(需要新增頁面時) `frontend-layering.md` 是歷史參考,後續以 `docs/architecture-strategy.md` 與 `src/**/GUIDE.md` 為準。 ## GUIDE 索引 | 範圍 | 指南 | |------|------| | `src` 總覽、資料流、template core、demo 邊界 | `src/GUIDE.md` | | route view 與薄 view 規則 | `src/views/GUIDE.md` | | maintenance demo view | `src/views/maint/GUIDE.md` | | Vue component 分層 | `src/components/GUIDE.md` | | base 元件 | `src/components/base/GUIDE.md` | | section 元件 | `src/components/sections/GUIDE.md` | | layout 邊界 | `src/components/layouts/GUIDE.md` | | page driver、command、layout composable | `src/composables/GUIDE.md` | | route 與 guard | `src/router/GUIDE.md` | | AppShell、tabs、global overlays | `src/shell/GUIDE.md` | | Pinia store | `src/stores/GUIDE.md` | | HTTP service / ky / API module | `src/services/GUIDE.md` | | domain model 與 page model 型別 | `src/models/GUIDE.md` | | 跨模組共用 API 型別 | `src/types/GUIDE.md` | | i18n 文案 | `src/language/GUIDE.md` | ## 預設修改策略 一般功能需求優先修改: - `src/views/*` - `src/components/sections/*` - `src/components/items/*` - `src/composables/page-drivers/*` - `src/composables/useCrudCommands.ts` - `src/stores/*` - `src/services/modules/*` - `src/router/routes.ts` - `src/language/*.json` 除非使用者明確要求,避免先修改 template core。template core 清單與 demo/example 邊界見 `src/GUIDE.md`。 ## 常用判斷 - 新 route:讀 `src/router/GUIDE.md`。 - 一般頁面:讀 `src/views/GUIDE.md`、`src/components/GUIDE.md`、`src/composables/GUIDE.md`。 - 維護頁:讀 `src/views/maint/GUIDE.md`。 - 查詢/列表頁(篩選 + 表格):讀 `src/components/sections/GUIDE.md`(`SectionQueryPage`)。 - 申請/填寫頁(送出按鈕):讀 `src/components/sections/GUIDE.md`(`SectionFormPage`)。 - layout / AppShell / tabs / global overlay:讀 `src/shell/GUIDE.md` 與 `src/components/layouts/GUIDE.md`。 - API 串接:讀 `src/services/GUIDE.md`。 - 跨頁共享狀態:讀 `src/stores/GUIDE.md`。 - 定義 page model 或 domain model 型別:讀 `src/models/GUIDE.md`。 - 共用 API 型別定義:讀 `src/types/GUIDE.md`。 - 錯誤頁:讀 `src/views/GUIDE.md`(ErrorShell 模式)與 `src/router/GUIDE.md`(錯誤頁路由慣例)。 - 語系文案:讀 `src/language/GUIDE.md`。 ## 修改前檢查 - 是否碰到 template core。 - 是否已有同類型範例可沿用。 - 是否需要新增 route。 - 是否應拆成 section / item。 - 是否應新增 page driver 或 command composable。 - 是否需要 store,或只需要頁面內 state。 - 是否應定義新的 model 型別(`src/models/`)。 - 是否需要更新語系、menu、breadcrumb、favorites。 ## 從視覺特徵選擇 section 元件 當收到 prototype 截圖或設計稿時,依畫面特徵選擇 section 外殼: | 特徵 | 選擇 | |------|------| | 有「送出/存檔」按鈕,且畫面為填寫表單(欄位 + 配合事項 + 動作按鈕) | `SectionFormPage` | | 有「查詢」按鈕,且畫面為篩選條件 + 結果表格/列表 | `SectionQueryPage` | | 純粹表格列表(無送出/查詢按鈕,只有 CRUD 操作) | 不用 section 外殼,直接組合 `v-data-table` | | 混合結構(有查詢也有表單填寫) | 評估是否拆成兩頁;若必須同頁,不用通用外殼 | 判斷順序:先看有無「送出/存檔」→ 再看有無「查詢」→ 其餘視為一般列表頁。 ## `.spec.json` 對照指南 當 LLM 依照 `GEN-FE-PROMPT` 讀取 `.ht/spec/{page}.spec.json` 後,依 `maintenanceContract.pageKind` 決定對應的 demo 與 composable 界面,再將 `.spec.json` 的 evidence 欄位對應到 composable 的 reactive state、computed 與 API calls。 ### query(查詢頁)→ `SectionQueryPage` 參考:`src/views/demos/SectionQueryPageDemo.vue`、`src/composables/page-drivers/useSectionsDemoPage.ts` 架構: ``` View(自含 page model + UI) → SectionQueryPage ↓ composable (page driver) ``` **composable 必須回傳:** | 名稱 | 型別 | 對應 `.spec.json` 來源 | |------|------|------------------------| | `queryFilters` | `Ref<{ 每個欄位 }>` | `pageContract.forms[0].fields` — 每個 field 建一個 key,型別依 `field.type`(text→string, select→string \| null,選項取自 `field.options`) | | `pageModel` | `ComputedRef<{ title, ... }>` | `title` 來自 `pageContract.title`;`backLabel` 固定為 `'返回'` | | `handleQuerySearch()` | 函式 | 觸發 `apiContract.endpoints` 中 `usage=search` 的 API call;呼叫時機對應 `bddContract.scenarios` 中 `type=query` 的 When | | `handleQueryBack()` | 函式 | 對應 `pageContract.actions` 中 `actionType=back` | | 表格資料 | 在 `pageModel` 中 | `tables[].headers` 對應表格欄;`sampleRows` 對應欄位格式 | **page component props:** - `v-model:query-filters` — 雙向綁定 `queryFilters` - `:page` — 傳入 `pageModel` **page component emits:** - `@search` → 呼叫 `handleQuerySearch` - `@back` → 呼叫 `handleQueryBack` ### application(申請/表單頁)→ `SectionFormPage` 參考:`src/views/demos/SectionFormPageDemo.vue` 架構: ``` View(自含 page model + UI) → SectionFormPage ↓ composable (page driver) ``` **composable 必須回傳:** | 名稱 | 型別 | 對應 `.spec.json` 來源 | |------|------|------------------------| | `demoForm`(應改名為 `formState`) | `Ref<{ 每個欄位 }>` | `pageContract.forms[0].fields` — text/select 建 key;不可編輯的 `readonly` 欄位不放進 formState,改從 `pageModel` 單向顯示 | | `pageModel` | `ComputedRef` | `title` 來自 `pageContract.title` | | `handleFormSubmit()` | 函式 | 觸發 `apiContract.endpoints` 中 `usage=create` 的 POST endpoint;呼叫前驗證 `apiCatalog.fieldRules`;呼叫時機對應 `bddContract.scenarios` 中 `type=application-submit` 的 When/Then | | `resetDemoForm()`(改為 `resetForm`) | 函式 | 對應 `pageContract.actions` 中 `actionType=reset` | | `handleFormBack()` | 函式 | 對應 `actionType=back` | **提交 payload 規則:** - `apiCatalog.fieldRules` 中的 `field` 與 `rule` 決定必填、長度、格式驗證 - 型別轉換依 `field.type`:number 欄位不可包成 string 送出 ### maintenance(維護/CRUD 頁)→ `maint/*` 參考:`src/views/maint/README.md` — 依資料結構選擇最接近的範本(EditableGrid / SingleRecord / MasterDetail A/B/C) **composable 必須回傳:** | 名稱 | 對應 `.spec.json` 來源 | |------|------------------------| | `search filters` | `pageContract.forms[0].fields` | | `table data / headers` | `pageContract.tables[].headers` + search API response | | `row action handlers` | `maintenanceContract.rowActions` — 每個 action 對應一個 handler;`enabledWhen` 決定啟用條件(如 `aprvYn === 'Z'` 時才能修改) | | `create/update/delete calls` | `apiContract.endpoints` 中對應的 POST/PUT/DELETE | **row action 狀態規則:** - `enabledWhen` 直接轉為 template 中的 `:disabled` 或 `v-if` 條件 - `maintenanceContract.businessRules` 中的額外限制一併套用 ### 通用規則 **entity 命名:** 所有 composable、component、store 的名稱以 `maintenanceContract.dataModel.primaryEntity` 為 entity 名,例如 primaryEntity=`FacilityApply` → `useFacilityApplyPage.ts` → `PageFacilityApply.vue`。 **API 串接:** 在 `src/services/modules/` 新增對應 entity 的 API module,method 名稱對齊 `apiContract.endpoints[].usage`(search/create/update/delete/print),path 對齊 `endpoint.path`。 **錯誤處理:** 檢查 `apiContract.errorHandling.format` — 若為 `ProblemDetailsWithValidationErrors`,須處理 `errors` 物件中的逐欄錯誤訊息;若為 `ProblemDetails`,只顯示 `detail`。 **語系文案:** 欄位 label 與按鈕文字取自 `pageContract.forms[].fields[].label` 和 `pageContract.actions[].label`,放入 `src/language/` 對應語系 key。 ## 完成前驗證 - Vue / TypeScript 結構有變更:`pnpm -s type-check` - 需要確認產物可建置:`pnpm -s build` - Markdown 或大量搬移:`git diff --check` - route、layout 或主要畫面流程有變更:啟動 dev server 並用瀏覽器確認,除非使用者明確不需要。 如果無法執行驗證,回報原因,不要宣稱已驗證。