diff --git a/docs/llm-development-guide.md b/docs/llm-development-guide.md index 8ab5eed..b9db877 100644 --- a/docs/llm-development-guide.md +++ b/docs/llm-development-guide.md @@ -8,13 +8,12 @@ ## 建議閱讀順序 -1. `README.md` +1. `src/GUIDE.md` 2. `docs/architecture-strategy.md` -3. `src/GUIDE.md` -4. 依變更範圍閱讀對應的 `src/**/GUIDE.md` -5. `docs/add-page-example.md`(需要新增頁面時) +3. 依 `maintenanceContract.pageKind` 閱讀對應的 `src/**/GUIDE.md`(查 `src/GUIDE.md` 中的「依 pageKind 選擇起點」表格) +4. `docs/add-page-example.md`(需要新增頁面時) -`docs/frontend-layering.md` 是歷史參考,後續以 `docs/architecture-strategy.md` 與 `src/**/GUIDE.md` 為準。 +`frontend-layering.md` 是歷史參考,後續以 `docs/architecture-strategy.md` 與 `src/**/GUIDE.md` 為準。 ## GUIDE 索引 @@ -92,6 +91,92 @@ 判斷順序:先看有無「送出/存檔」→ 再看有無「查詢」→ 其餘視為一般列表頁。 +## `.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/components/pages/PageSectionQueryPageDemo.vue`、`src/composables/page-drivers/useSectionsDemoPage.ts` + +架構: +``` +View (薄層) → composable (page driver) → PageSectionQueryPageDemo → SectionQueryPage +``` + +**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`、`src/components/pages/PageSectionFormPageDemo.vue` + +架構: +``` +View (薄層) → composable (page driver) → PageSectionFormPageDemo → SectionFormPage +``` + +**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 送出 + +**page component emits:** +- `@submit` → 呼叫 `handleFormSubmit` +- `@reset` → 呼叫 `resetForm` +- `@back` → 呼叫 `handleFormBack` + +### 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` diff --git a/src/components/GUIDE.md b/src/components/GUIDE.md index 3b2514b..531388b 100644 --- a/src/components/GUIDE.md +++ b/src/components/GUIDE.md @@ -1,37 +1,58 @@ -# Components Guide +# Src Guide -`src/components` 放 Vue UI 元件,包含 layout、page component、feature/domain component 與少量跨頁共用元件。 +`src` 是 template 使用者主要修改的區域。新增功能時,先從 route view、page component 與 page driver 開始,除非需求明確牽涉 app shell、登入、router guard 或 HTTP core,否則不要先改 template core。 -## 分層 - -| 目錄 | 說明 | 指南 | -|------|------|------| -| `pages/` | 完整頁面組裝,檔名使用 `Page` 前綴 | — | -| `sections/` | 頁面區塊容器,例如搜尋區、表格、dialog shell、panel | `sections/GUIDE.md` | -| `items/` | 單筆資料、欄位群組或原子級呈現 | `items/GUIDE.md` | -| `layouts/` | App shell layout | `layouts/GUIDE.md` | -| `base/` | 真正跨頁共用且不屬於特定 domain 的基礎元件 | `base/GUIDE.md` | -| `login/` | 登入頁專用 UI | — | -| `maint/` | maintenance demo 舊有或領域型 UI 元件 | — | - -## 規則 - -- 不要假設 `src/components` 會自動全域註冊元件;需要使用元件時,依照目前 Vue SFC 慣例明確 import。 -- 直接被 route 載入的檔案放在 `src/views`,不要放在 `src/components`。 -- 負責完整頁面主畫面組裝的元件使用 `Page` 前綴。 -- 只服務單一功能或 domain 的元件,放在對應資料夾,不要放進 `base`。 -- layout 元件只處理 app shell 與框架 UI,不放頁面專屬業務流程。 -- `pages` 可組合 sections/items,但不直接處理 API。 -- `sections` 決定布局與區塊互動,不知道 route。 -- `items` 不知道自己在表格、grid 或 dialog 中。 - -## 命名 - -- Page component:`PageXxx.vue` -- Section component:`SectionXxx.vue` -- Item component:`ItemXxx.vue` -- Layout component:依 shell/區塊命名,例如 `MainLayout.vue` +Template Core 與 Demo/Example 的完整清單見 `src/README.md`。 ## 資料流 -component 以 props 接收資料,以 emit 回報使用者事件。需要跨頁共享的狀態交給 `src/stores`;可重用流程或較複雜 UI state 放到 `src/composables`。 +```txt +router -> AppShell -> layout -> view(Page Driver) -> Page Component -> Section -> Item + ↓ + page driver / command composable -> store -> service +``` + +## 主要目錄 + +- `views/`:route entry,維持薄層,只做 route wiring 與 page driver 掛載。詳見 `src/views/GUIDE.md`。 +- `components/`:Vue UI 元件,依 pages / sections / items / layouts / base 分層。詳見 `src/components/GUIDE.md`。 +- `composables/`:page driver、command flow、layout flow 與可重用狀態流程。詳見 `src/composables/GUIDE.md`。 +- `router/`:route、layout meta、auth meta 與 guard。詳見 `src/router/GUIDE.md`。 +- `shell/`:AppShell、tabs、global overlays。詳見 `src/shell/GUIDE.md`。 +- `stores/`:跨頁共享狀態與快取。詳見 `src/stores/GUIDE.md`。 +- `services/`:HTTP client、API module、token/session、錯誤處理。詳見 `src/services/GUIDE.md`。 +- `language/`:Vue I18n 文案。詳見 `src/language/GUIDE.md`。 + +## 依 pageKind 選擇起點 + +`.spec.json` 中 `maintenanceContract.pageKind` 決定使用哪一種 demo 架構。完整欄位對照見 `docs/llm-development-guide.md` 的「`.spec.json` 對照指南」。 + +| pageKind | 參考 Demo | 讀取 GUIDE | +| ------------- | ------------------------------------------ | -------------------------------------------------------- | +| `query` | `src/views/demos/SectionQueryPageDemo.vue` | `src/components/sections/GUIDE.md`(SectionQueryPage) | +| `application` | `src/views/demos/SectionFormPageDemo.vue` | `src/components/sections/GUIDE.md`(SectionFormPage) | +| `maintenance` | `src/views/maint/*` | `src/views/maint/README.md` + `src/views/maint/GUIDE.md` | +| `auth` | `src/views/Login.vue` | `src/views/GUIDE.md` | +| `print` | query 或 application demo | 同 query / application | +| `chooser` | 不適用 demo | 轉為 route group 或 tab | + +## 新功能流程 + +1. 依 `pageKind` 選擇最接近的 demo。 +2. 在 `src/views//` 新增 route view(薄層,只掛 page driver)。 +3. 在 `src/composables/page-drivers/` 新增 page driver composable。 +4. 在 `src/components/pages/` 新增 page component。 +5. 若畫面有獨立區塊,拆到 `src/components/sections/*`。 +6. 若區塊內有欄位群組,拆到 `src/components/items/*`。 +7. 在 `src/services/modules/` 新增 API module。 +8. 在 `src/models/` 定義 page model 與 domain model 型別。 +9. 在 `src/router/routes.ts` 新增 route。 +10. 在 `src/language/` 新增語系文案。 + +跨頁共享狀態才新增或修改 `src/stores/*`。 + +## 驗證 + +- Vue / TypeScript 結構變更:`pnpm -s type-check` +- 需要確認產物:`pnpm -s build` +- route、layout 或主要畫面流程變更:啟動 dev server 並做瀏覽器檢查,除非使用者明確不需要。