docs: expand LLM guide with spec-to-page mapping

Update the LLM development guide to prioritize src/GUIDE.md and add
detailed `.spec.json` mapping rules for query, application, and
maintenance pages. Clarify how page contracts, API contracts, actions,
validation, naming, error handling, and i18n should drive generated
composables and page components.docs: expand LLM guide with spec-to-page mapping

Update the LLM development guide to prioritize src/GUIDE.md and add
detailed `.spec.json` mapping rules for query, application, and
maintenance pages. Clarify how page contracts, API contracts, actions,
validation, naming, error handling, and i18n should drive generated
composables and page components.
This commit is contained in:
skytek_xinliang
2026-05-26 17:09:41 +08:00
parent b5be5b4448
commit 799b16578d
2 changed files with 143 additions and 37 deletions
+90 -5
View File
@@ -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 modulemethod 名稱對齊 `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`