diff --git a/docs/add-page-example.md b/docs/add-page-example.md
index d8bc437..58cf1d4 100644
--- a/docs/add-page-example.md
+++ b/docs/add-page-example.md
@@ -4,56 +4,99 @@
範例功能:`reports`
-## 1. 新增 route view
+目前新增一般頁面的預設資料流:
-```vue
-
-
-
-
-
-
+```txt
+router -> view -> page driver -> page component -> sections/items
+ ↓
+ store/composable -> service
```
-view 的責任是頁面資料組裝與事件協調。畫面區塊交給 feature component。
+## 1. 新增 page driver
-## 2. 新增 feature component
+頁面資料、事件與暫時 UI state 優先放在 page driver,view 只負責掛載。
-```vue
-
-
- 報表清單
+ {{ page.title }}
| 名稱 |
負責單位 |
+ 操作 |
-
+
| {{ row.title }} |
{{ row.owner }} |
+
+
+ 開啟
+
+ |
@@ -61,9 +104,27 @@ defineProps<{
```
-component 以 props 接收資料,以 emit 回報事件。不要在 component 裡直接處理 route 或底層 HTTP。
+若畫面是固定的「篩選條件 + 查詢按鈕 + 結果表格」,優先使用 `components/sections/SectionQueryPage.vue`。若是「表單欄位 + 送出/存檔按鈕」,優先使用 `components/sections/SectionFormPage.vue`。
-## 3. 加入 route
+## 3. 新增 route view
+
+view 維持薄層,只呼叫 page driver 並掛載 page component。
+
+```vue
+
+
+
+
+
+
+```
+
+## 4. 加入 route
route 加在 `src/router/routes.ts` 的 `routes` 陣列中,並放在 `/:pathMatch(.*)*` catch-all route 前面。
@@ -84,9 +145,9 @@ route 加在 `src/router/routes.ts` 的 `routes` 陣列中,並放在 `/:pathMa
- menu 來源目前由 `src/stores/menu.ts` 轉換後端選單資料。
- breadcrumb 會依 route path、menu/favorite items 與 fallback title 產生。
- 新功能若使用後端選單,優先調整後端選單資料或對應 API mock,不要把頁面專屬選單邏輯塞進 layout。
-- 若只是新增 route,通常不需要修改 `MainLayout.vue`。
+- 若只是新增 route,通常不需要修改 `MainLayout.vue` 或 `src/shell/*`。
-## 4. 需要 API 時新增 service module
+## 5. 需要 API 時新增 service module
```ts
// src/services/modules/reports.ts
@@ -107,9 +168,11 @@ export const reportsApi = {
service 只封裝 HTTP 細節,不持有 UI 狀態。
-`httpClient` 的 `baseURL` 來自 `VITE_API_BASE_URL`。template 預設值見 `.env.example`,通常使用 `/service/api` 搭配 Vite proxy。
+`httpClient` 的 `baseURL` 來自 `VITE_API_BASE_URL`,沒有設定時預設 `/service/api`。開發模式下,Vite proxy 會將 `/service/*` 轉送到 `VITE_PROXY_TARGET`。
-## 5. 需要共享狀態時新增 store
+## 6. 需要共享狀態時新增 store
+
+只有跨頁共享、需要快取、或全域狀態才新增 store。單頁暫時狀態留在 view、component 或 composable。
```ts
// src/stores/reports.ts
@@ -139,15 +202,18 @@ export const useReportsStore = defineStore('reports', () => {
})
```
-只有跨頁共享、需要快取、或全域狀態才新增 store。單頁暫時狀態留在 view、component 或 composable。
-
-## 6. 驗證
+## 7. 驗證
至少執行:
```bash
-pnpm type-check
-pnpm build
+pnpm -s type-check
+```
+
+需要確認建置產物時再執行:
+
+```bash
+pnpm -s build
```
若有 route、layout 或主要互動流程變更,再啟動 dev server 並用瀏覽器確認。
diff --git a/docs/analyse-now.md b/docs/analyse-now.md
index 879c923..2310a07 100644
--- a/docs/analyse-now.md
+++ b/docs/analyse-now.md
@@ -1,47 +1,65 @@
## 二、我們專案的現況診斷
-### 2.1 App.vue 過度臃腫(~590 行)
+本文件是 `docs/architecture-strategy.md` 第二章的現況快照。分層細節以 `docs/architecture-strategy.md` 與 `src/**/GUIDE.md` 為準。
-| 職責 | 行數 | 應屬層級 |
-|------|------|----------|
-| Layout 切換 | ~20 | App Shell |
-| Tabs 管理 | ~80 | Page Driver |
-| Breadcrumb 組裝 | ~40 | Layout |
-| Favorites 管理 | ~60 | Store |
-| Search Dialog | ~80 | App Shell / Widget |
-| Message Dialog | ~60 | App Shell / Widget |
-| Snackbar | ~10 | Global Overlay |
-| Logout / Force logout | ~30 | Auth Flow |
-| HTTP Toast | ~20 | Service Layer |
+### 2.1 App Shell 已拆分
-- **問題**:App.vue 同時承擔 App Shell、Page Driver、Global Widget、Auth Flow 四種責任。
-- **對比**:App Store 的 `App.svelte` 只有 161 行,只負責 `Navigation + PageResolver + Footer`。
+`App.vue` 目前只掛載 `src/shell/AppShell.vue`,不再承擔 layout props、tabs、搜尋 dialog、訊息 dialog 或 snackbar 的具體組裝。
-### 2.2 Views 過厚(SingleRecord.vue ~830 行)
+目前責任分布:
-- 混雜:表格呈現、搜尋表單、dialog 模板、表單狀態、CRUD 流程、驗證邏輯、分頁、snackbar。
-- **對比**:App Store 的 `ProductPage.svelte` 只有 77 行,只負責「把 page 轉成 DefaultPageRequirements + 一個 slot override」。
+| 職責 | 目前位置 |
+|------|----------|
+| Layout 切換 | `src/shell/AppShell.vue` |
+| Tabs / keep-alive router-view | `src/shell/AppTabs.vue` |
+| Breadcrumb / favorites / menu wiring | `src/composables/layout/useAppShell.ts` + `AppShell.vue` |
+| Search Dialog / Message Dialog / Snackbar | `src/shell/GlobalOverlays.vue` |
+| Logout / force logout | `src/composables/layout/useAppShell.ts` |
+| HTTP Toast | `src/services/http-toast.ts` + `GlobalOverlays.vue` |
-### 2.3 缺乏統一的頁面資料門面
+### 2.2 Views 已大幅變薄
-```
-現況:
- view → store → service(直接鏈式呼叫)
- view 自己管理 loading / error / dialog visible
+維護頁與一般頁面目前多數已轉為 route-level wiring:
-App Store:
- UI → jet.dispatch(intent) → runtime → controller → page model
- UI 只接收 page model,不管理載入狀態
+- `Home.vue`:呼叫 `useHomePage()`,掛載 `PageHome`。
+- `Settings.vue`:呼叫 `useSettingsPage()`,掛載 `PageSettings`。
+- `FncPage.vue`:呼叫 `useFunctionPage()`,掛載 `PageFunction`。
+- `views/maint/*`:呼叫對應 page driver,掛載 `components/pages/*Maintenance.vue`。
+
+`SingleRecord.vue` 已不再直接管理 store mutation、大型 dialog 模板、表格分頁與 CRUD 細節;這些流程已移到 page driver、section component、item component 與 command composable。
+
+`Login.vue` 是 template core 例外,仍負責登入頁組合、功能開關、小型提示 dialog 與登入流程協調。登入頁的 captcha、announcement、忘記密碼與記住帳號流程已透過 composable / props / emits 拆分,後續調整應維持該模式。
+
+### 2.3 Page Driver / Command / Page Component 已落地
+
+目前已存在的主要分層:
+
+```txt
+view -> page driver -> page component -> section/item
+ ↓
+ command/store/service
```
-### 2.4 Dialog 狀態與模板內嵌於 View
+- `src/composables/page-drivers/*`:組裝 page model、route/query 轉換與頁面事件。
+- `src/composables/commands/useCrudCommands.ts`:承接維護頁 CRUD 命令流程。
+- `src/components/pages/*`:完整頁面的主畫面組裝。
+- `src/components/sections/*`:搜尋區、表格區、表單 dialog/panel、表單/查詢頁外殼。
+- `src/components/items/*`:欄位群組或單筆資料呈現。
-- `SingleRecord.vue` 內含 5 個 `ConfirmDialog` 實例 + 1 個大 form overlay。
-- 任何 dialog 更動都需要修改 view 檔案。
+### 2.4 Dialog 與區塊拆分狀態
-### 2.5 沒有容器/內容分離的 Section 層
+維護頁的大型 dialog 與表單欄位已從 view 抽出:
-- 表格、表單、搜尋區塊都是直接寫在 view 或 page component 中。
-- 缺乏類似 `ShelfItemLayout` 的通用佈局抽象:「這一區是水平捲軸還是網格」應該由容器決定,裡面的內容元件不應該知道。
+- `SectionFormPanel.vue`:維護頁表單 overlay/dialog shell。
+- `MntDialogCard.vue`、`MntRecordNavToolbar.vue`:維護頁 dialog 內部骨架。
+- `ItemFormFieldGroup.vue`:表單欄位群組。
----
+新增頁面時,若只是小型提示 dialog 且只屬於單一路由,可先留在 page driver / page component。若 dialog 包含大型表單、確認流程或可重用骨架,優先抽到 section 或 feature component。
+
+### 2.5 仍需注意的邊界
+
+- `src/models/page.ts` 目前主要服務 maintenance page model;部分頁面仍在各自 page driver 內定義局部 page model 型別。
+- `components/maint/*` 與 maintenance page components 屬於 demo / maintenance 領域,不應直接升格為全域 base 元件。
+- `src/components/base` 目前只放跨頁共用基礎元件,例如 `DraggableDialog`、`BaseFormTextField`、`BaseFormSelect`。
+- `src/stores/app.ts` 仍是 Pinia scaffold,尚未承擔實際 app state。
+- 一般功能需求不應修改 `App.vue`、`src/shell/*`、layout、router guard 或 HTTP core,除非需求明確牽涉這些 template core。
diff --git a/docs/frontend-layering.md b/docs/frontend-layering.md
index 25574b7..67a4896 100644
--- a/docs/frontend-layering.md
+++ b/docs/frontend-layering.md
@@ -2,17 +2,17 @@
## 目的
-這份文件只描述目前 repo 已經落地的前端分層與命名規則,讓後續新增檔案、搬移檔案、或重構時有一致判斷基準。
+這份文件描述目前 repo 已經落地的前端分層與命名規則,讓後續新增檔案、搬移檔案或重構時有一致判斷基準。
+
+本文件是現況快照;新增功能與重構的細節規範以 `docs/architecture-strategy.md`、`docs/llm-development-guide.md` 與各層 `src/**/GUIDE.md` 為準。
目前專案的主要責任鏈如下:
-- `router` 決定 route 與 layout meta
-- `App.vue` 根據 route meta 組裝 app shell 與全域 UI
-- `views` 承接路由入口與頁面資料協調
-- `components` 承接 layout、page component、domain component 與較細的 UI 區塊
-- `composables` 承接可重用流程與 UI state
-- `stores` 承接跨頁狀態、快取與全域顯示狀態
-- `services` 承接 HTTP client、API 模組、token 與錯誤處理
+```txt
+router -> App.vue -> AppShell -> layout -> view -> page component -> section -> item
+ ↓
+ page driver / command composable -> store -> service
+```
## 目前目錄的責任邊界
@@ -26,93 +26,117 @@
責任:
-- 定義 route 與 route meta
-- 指定頁面使用哪種 layout
-- 串接導航守衛
+- 定義 route 與 route meta。
+- 指定頁面使用哪種 layout。
+- 串接導航守衛。
-目前 `meta.layout` 已是 app shell 切換的正式入口:
+目前 `meta.layout` 是 app shell 切換的正式入口:
-- `default` 走 [MainLayout.vue](../src/components/layouts/MainLayout.vue)
-- `none` 走 [PlainLayout.vue](../src/components/layouts/PlainLayout.vue)
+- `default` 走 [MainLayout.vue](../src/components/layouts/MainLayout.vue)。
+- `none` 走 [PlainLayout.vue](../src/components/layouts/PlainLayout.vue)。
-### `src/App.vue`
+### `src/App.vue` 與 `src/shell`
-[App.vue](../src/App.vue) 目前不是單純掛載入口,而是實際的應用組裝層。
+[App.vue](../src/App.vue) 目前只掛載 [AppShell.vue](../src/shell/AppShell.vue),不再直接承擔全域 UI 組裝。
-目前承擔的責任包含:
+`src/shell` 是 App Shell 層:
-- 根據 `route.meta.layout` 切換 layout
-- 組裝 breadcrumb / favorites / menu 等 layout props
-- 放置全域搜尋結果 dialog
-- 放置全域訊息中心 dialog
-- 放置全域 snackbar
-- 串接 layout event 與路由跳轉
+- [AppShell.vue](../src/shell/AppShell.vue):layout 切換、layout props/events、breadcrumb actions、tabs router-view 與 `GlobalOverlays` 掛載。
+- [AppTabs.vue](../src/shell/AppTabs.vue):default layout 下的 tabs 與 keep-alive router-view 容器。
+- [GlobalOverlays.vue](../src/shell/GlobalOverlays.vue):全域 snackbar、搜尋 dialog、訊息 dialog。
判斷原則:
-- 與整個 app shell 共享、且不屬於單一路由頁面的 UI,可留在 `App.vue`
-- 只屬於單一路由頁面的對話框或互動,不應堆到 `App.vue`
+- 與整個 app shell 共享、且不屬於單一路由頁面的 UI,可放在 `src/shell`。
+- 只屬於單一路由頁面的對話框或互動,不應放進 `src/shell`。
+- shell 狀態協調優先放在 `src/composables/layout/useAppShell.ts`。
### `src/views`
-`views` 目前整體方向是「路由入口 + 頁面資料協調 + 頁面事件協調」。
+`views` 是 route entry,方向是薄層:呼叫 page driver、掛載 page component、協調 route-level 事件。
-目前較薄的 view:
+目前較典型的薄 view:
- [Home.vue](../src/views/Home.vue)
-- [Login.vue](../src/views/Login.vue)
-- [EditableGrid.vue](../src/views/maint/EditableGrid.vue)
-- [Forbidden.vue](../src/views/errors/Forbidden.vue)
-- [ServerError.vue](../src/views/errors/ServerError.vue)
-- [ServiceUnavailable.vue](../src/views/errors/ServiceUnavailable.vue)
-- [NetworkError.vue](../src/views/errors/NetworkError.vue)
-- [Maintenance.vue](../src/views/errors/Maintenance.vue)
-- [NotFound.vue](../src/views/errors/NotFound.vue)
-- [ErrorShell.vue](../src/views/errors/ErrorShell.vue)
-- [FncPage.vue](../src/views/FncPage.vue)
- [Settings.vue](../src/views/Settings.vue)
-
-目前仍偏厚的 view:
-
+- [FncPage.vue](../src/views/FncPage.vue)
- [SingleRecord.vue](../src/views/maint/SingleRecord.vue)
+- [EditableGrid.vue](../src/views/maint/EditableGrid.vue)
- [MasterDetailA.vue](../src/views/maint/MasterDetailA.vue)
- [MasterDetailB.vue](../src/views/maint/MasterDetailB.vue)
- [MasterDetailC.vue](../src/views/maint/MasterDetailC.vue)
+錯誤頁集中在 `src/views/errors`,通常使用 `meta.layout = 'none'`,並由 [ErrorShell.vue](../src/views/errors/ErrorShell.vue) 共用錯誤頁骨架。
+
+[Login.vue](../src/views/Login.vue) 是 template core 例外:它仍負責登入頁組合、功能開關、小型提示 dialog 與登入流程協調。登入頁 UI 拆在 `components/login/*`,captcha 與 announcement 流程拆在頂層 login composable。
+
`views` 應遵守的原則:
-- 可以持有 route、store、頁面資料組裝、頁面事件協調
-- 可以管理只屬於該頁的 dialog 顯示狀態
-- 不應長期承擔大量可抽出的模板片段
-- 不應把可重用流程直接留在頁面內重複複製
+- 可以持有 route、page driver 掛載、頁面資料組裝與頁面事件協調。
+- 可以管理只屬於該頁的小型 dialog 顯示狀態。
+- 不應長期承擔大型表格、表單、dialog 模板或可重用流程。
+- 不應直接處理底層 HTTP 細節。
### `src/components`
-目前 `components` 已經分成幾種不同角色,不能再用單一規則描述。
+`components` 依角色分層,不再用單一規則描述。
-#### 1. 頁面型元件
+#### 1. Root page/template components
-目前以下元件實際上扮演 page component:
+目前仍放在 `src/components` 根目錄的頁面外殼:
- [PageLogin.vue](../src/components/PageLogin.vue)
- [PageIndex.vue](../src/components/PageIndex.vue)
- [PageMaint.vue](../src/components/PageMaint.vue)
-這些檔案的責任是:
+這些是既有 template 頁面外殼或登入頁組裝元件。新增一般功能頁時,優先使用 `src/components/pages`。
-- 接收 view 組好的資料與事件
-- 組裝某個完整頁面的主畫面
-- 再往下使用較小的子元件或 domain component
+#### 2. `components/pages`
-命名規則:
+`components/pages` 是完整頁面主畫面組裝層:
-- 只要是 page component,檔名以 `Page` 為前綴
-- page component 可以放在 `components` 根目錄
-- 不要把 page component 丟進 `base`
+- [PageHome.vue](../src/components/pages/PageHome.vue)
+- [PageSettings.vue](../src/components/pages/PageSettings.vue)
+- [PageFunction.vue](../src/components/pages/PageFunction.vue)
+- [PageMaintenance.vue](../src/components/pages/PageMaintenance.vue)
+- [PageEditableGridMaintenance.vue](../src/components/pages/PageEditableGridMaintenance.vue)
+- [PageMasterDetailAMaintenance.vue](../src/components/pages/PageMasterDetailAMaintenance.vue)
+- [PageMasterDetailBMaintenance.vue](../src/components/pages/PageMasterDetailBMaintenance.vue)
+- [PageMasterDetailCMaintenance.vue](../src/components/pages/PageMasterDetailCMaintenance.vue)
-#### 2. `components/login`
+責任:
-登入頁的較細 UI 區塊已集中到:
+- 接收 view/page driver 組好的資料與事件。
+- 組裝完整頁面的主要 section 順序。
+- 再往下使用 sections、items、feature/domain components。
+
+#### 3. `components/sections`
+
+`components/sections` 是頁面區塊容器:
+
+- [SectionSearchPanel.vue](../src/components/sections/SectionSearchPanel.vue)
+- [SectionDataTable.vue](../src/components/sections/SectionDataTable.vue)
+- [SectionFormPanel.vue](../src/components/sections/SectionFormPanel.vue)
+- [SectionFormPage.vue](../src/components/sections/SectionFormPage.vue)
+- [SectionQueryPage.vue](../src/components/sections/SectionQueryPage.vue)
+
+責任:
+
+- 決定區塊布局與區塊互動。
+- 以 props 接收資料,以 emit 回報事件。
+- 不知道 route,不直接呼叫 API。
+
+#### 4. `components/items`
+
+`components/items` 是欄位群組或單筆資料呈現層:
+
+- [ItemFormFieldGroup.vue](../src/components/items/ItemFormFieldGroup.vue)
+
+item 不應知道自己被放在表格、grid、dialog 或頁面哪個位置。
+
+#### 5. `components/login`
+
+登入頁的較細 UI 區塊集中在:
- [CreateAccountLink.vue](../src/components/login/CreateAccountLink.vue)
- [LoginAnnouncementBoard.vue](../src/components/login/LoginAnnouncementBoard.vue)
@@ -123,56 +147,12 @@
- [LoginToolBar.vue](../src/components/login/LoginToolBar.vue)
- [LoginVerify.vue](../src/components/login/LoginVerify.vue)
-這一層的定位是:
+這一層服務 `PageLogin`,不是全域 base library。
-- 服務 `PageLogin`
-- 屬於 login 頁面家族
-- 不是全域 base library
+#### 6. `components/maint`
-#### 3. `components/base`
+`components/maint` 是 maintenance demo / domain component 區域:
-目前 `components/base` 只剩下:
-
-- [DraggableDialog.vue](../src/components/base/DraggableDialog.vue)
-
-目前判斷原則很直接:
-
-- `base` 只放真正可跨頁重用、且不屬於特定 domain 的元件
-- 若元件只服務單一頁面家族或單一 domain,優先放回對應資料夾
-
-#### 4. `components/layouts`
-
-目前 layout 實作集中於:
-
-- [MainLayout.vue](../src/components/layouts/MainLayout.vue)
-- [PlainLayout.vue](../src/components/layouts/PlainLayout.vue)
-- `src/components/layouts/main-layout/*`
-
-其中 `main-layout/*` 是 `MainLayout` 底下拆出的骨架子元件:
-
-- [AppBarBreadcrumbCol.vue](../src/components/layouts/main-layout/AppBarBreadcrumbCol.vue)
-- [AppBarFavoritesCol.vue](../src/components/layouts/main-layout/AppBarFavoritesCol.vue)
-- [AppBarTopCol.vue](../src/components/layouts/main-layout/AppBarTopCol.vue)
-- [DrawerDesktopMenu.vue](../src/components/layouts/main-layout/DrawerDesktopMenu.vue)
-- [DrawerMobileFavoritesPanel.vue](../src/components/layouts/main-layout/DrawerMobileFavoritesPanel.vue)
-- [DrawerMobileMenuPanel.vue](../src/components/layouts/main-layout/DrawerMobileMenuPanel.vue)
-
-layout 應只承擔:
-
-- app shell
-- drawer / app bar / favorites / breadcrumb 等框架 UI
-- 與 layout 視覺結構直接相關的互動
-
-layout 不應承擔:
-
-- 頁面專屬業務流程
-- 特定 domain 的資料規則
-
-#### 5. `components/maint`
-
-這個目錄目前是最接近 feature folder 的區域,放 maintenance 領域的 page component 與 domain component:
-
-- [PageMaint.vue](../src/components/PageMaint.vue)
- [CommonConfirmDialog.vue](../src/components/maint/CommonConfirmDialog.vue)
- [EditableGrid.vue](../src/components/maint/EditableGrid.vue)
- [MasterFileFormFields.vue](../src/components/maint/MasterFileFormFields.vue)
@@ -180,46 +160,48 @@ layout 不應承擔:
- [MntRecordNavToolbar.vue](../src/components/maint/MntRecordNavToolbar.vue)
- `master-detail/*`
-`master-detail/*` 目前屬於維護頁專用的較細組件群:
+若只是維護頁專用子元件,不要搬到 `base`。
-- [CourseMobilePanel.vue](../src/components/maint/master-detail/CourseMobilePanel.vue)
-- [DetailCollapseGropus.vue](../src/components/maint/master-detail/DetailCollapseGropus.vue)
-- [DetailFullHeightPanel.vue](../src/components/maint/master-detail/DetailFullHeightPanel.vue)
-- [DetailNavigation.vue](../src/components/maint/master-detail/DetailNavigation.vue)
-- [DetailSidePanel.vue](../src/components/maint/master-detail/DetailSidePanel.vue)
-- [DetailSimpleList.vue](../src/components/maint/master-detail/DetailSimpleList.vue)
+#### 7. `components/layouts`
-結論:
+layout 實作集中於:
-- `components/maint` 主要扮演 maintenance domain component 層
-- `CommonConfirmDialog` 可以直接在 maintenance 頁或元件使用,不需要再包一層 CRUD dialog aggregator
-- 若只是維護頁專用子元件,不要搬到 `base`
+- [MainLayout.vue](../src/components/layouts/MainLayout.vue)
+- [PlainLayout.vue](../src/components/layouts/PlainLayout.vue)
+- `src/components/layouts/main-layout/*`
+
+layout 只承擔 app shell、drawer、app bar、favorites、breadcrumb 等框架 UI,不承擔頁面專屬業務流程。
+
+#### 8. `components/base`
+
+`components/base` 放真正跨頁共用且不屬於特定 domain 的基礎元件:
+
+- [DraggableDialog.vue](../src/components/base/DraggableDialog.vue)
+- [BaseFormTextField.vue](../src/components/base/BaseFormTextField.vue)
+- [BaseFormSelect.vue](../src/components/base/BaseFormSelect.vue)
+
+只服務單一頁面家族或單一 domain 的元件不要放進 `base`。
### `src/composables`
-目前已明確分成兩組:
+目前 composables 分成:
-- `composables/layout/*`
-- `composables/maint/*`
+- `page-drivers/*`:頁面資料協調與 page model 組裝。
+- `commands/*`:命令式副作用流程,例如 create/edit/save/delete。
+- `layout/*`:AppShell / layout 狀態與事件協調。
+- `maint/*`:maintenance demo 的表單、CRUD、editable grid 狀態。
+- 頂層 login / utility composable:`useLoginCaptcha.ts`、`useLoginAnnouncements.ts`、`useApiCall.ts`。
-代表性檔案:
+責任:
-- [useAdminLayoutState.ts](../src/composables/layout/useAdminLayoutState.ts)
-- [useThemeToggle.ts](../src/composables/layout/useThemeToggle.ts)
-- [useMaintenanceCrudFlow.ts](../src/composables/maint/useMaintenanceCrudFlow.ts)
-- [useStudentMaintenanceForm.ts](../src/composables/maint/useStudentMaintenanceForm.ts)
-- [useEditableStudentGrid.ts](../src/composables/maint/useEditableStudentGrid.ts)
-- [useApiCall.ts](../src/composables/useApiCall.ts)
-
-`composables` 的責任:
-
-- 放可重用流程
-- 放可測試的 UI state
-- 放與模板結構耦合較低的狀態機
+- 放可重用流程。
+- 放可測試的 UI state。
+- 放與模板結構耦合較低的狀態機。
+- 不 import component 或 view。
### `src/stores`
-目前 store 已經是正式分層的一部分,而不只是暫時狀態容器。
+目前 store 是跨頁共享狀態、快取與全域顯示狀態的正式分層。
代表性檔案:
@@ -230,25 +212,20 @@ layout 不應承擔:
- [favorites.ts](../src/stores/favorites.ts)
- [messages.ts](../src/stores/messages.ts)
- [snackbar.ts](../src/stores/snackbar.ts)
-- [loginAnnouncements.ts](../src/stores/loginAnnouncements.ts)
- [students.ts](../src/stores/students.ts)
- [semesters.ts](../src/stores/semesters.ts)
責任:
-- 承接跨頁共享狀態
-- 承接畫面快取與顯示狀態
-- 作為 view 與 services 之間的狀態收斂點
-- `app.ts` 目前是空的 Pinia scaffold,尚未承擔實際 app state
+- 承接跨頁共享狀態。
+- 承接畫面快取與全域顯示狀態。
+- 作為 view/page driver/composable 與 services 之間的狀態收斂點。
-規則:
-
-- store 檔案直接放在 `src/stores/*.ts`
-- 不要建立 `src/stores/stores/*` 這類重複巢狀目錄
+`app.ts` 目前是空的 Pinia scaffold,尚未承擔實際 app state。
### `src/services`
-`services` 現在已經是一層明確的資料存取邊界,不應再被視為附屬工具資料夾。
+`services` 是 HTTP 與外部 API 邊界。
代表性檔案:
@@ -263,101 +240,93 @@ layout 不應承擔:
責任:
-- 提供 HTTP client
-- 封裝 API 模組
-- 統一 token、session 與錯誤處理
+- 提供 `httpClient`。
+- 封裝 API 模組。
+- 統一 token、session 與錯誤處理。
規則:
-- 元件不直接處理底層 HTTP 細節
-- 可共享的請求流程優先收斂到 store 或 composable,再由它們呼叫 service
+- 元件不直接處理底層 HTTP 細節。
+- service module 不持有 UI 狀態。
+- 可共享的請求流程優先收斂到 store、page driver 或 composable,再由它們呼叫 service。
## 目前已落地的分層模式
-### 模式 1:`view -> page component -> page family components`
+### 模式 1:`view -> page driver -> page component`
已落地頁面:
-- `Login`
- `Home`
-
-目前的穩定模式是:
-
-- `view` 負責資料準備與事件協調
-- page component 負責頁面主畫面組裝
-- 較細的視覺區塊再拆到對應頁面家族資料夾,例如 `components/login/*`
-
-### 模式 2:`view -> page component / domain components + maint composables`
-
-已落地區域:
-
+- `Settings`
+- `FncPage`
- `views/maint/*`
-- `components/maint/*`
-- `composables/maint/*`
-這一層目前是 maintenance 領域最清楚的結構:
+穩定模式:
-- `views/maint/*` 承接 route 與頁面流程協調
-- [PageMaint.vue](../src/components/PageMaint.vue) 承接維護頁共用頁面骨架
-- `components/maint/*` 承接維護頁專用元件
-- `composables/maint/*` 承接 CRUD 流程、表單狀態與 editable grid 狀態
+- view 負責掛載 page driver 與 page component。
+- page driver 負責 page model、事件與頁面狀態協調。
+- page component 負責頁面主畫面組裝。
-[EditableGrid.vue](../src/views/maint/EditableGrid.vue) 是目前最接近薄 view 的 maintenance 頁面。
+### 模式 2:`Login.vue -> PageLogin -> login components/composables`
-### 模式 3:`router meta -> App.vue -> layout`
+登入頁是 template core,功能開關集中在 `Login.vue`:
+
+- `withCaptcha`
+- `withAnnouncement`
+- `withForgotPassword`
+- `withRememberAccount`
+
+資料流與 side effect 分別由 `useLoginCaptcha()`、`useLoginAnnouncements()`、`PageLogin` 與 `LoginForm` 承接。
+
+### 模式 3:`router meta -> AppShell -> layout`
這一層已正式成立:
-- route 決定 layout 類型
-- `App.vue` 決定套用哪個 shell
-- layout 專注在骨架與共用框架 UI
-
-這代表 layout 的責任邊界不應再回頭混入頁面內部流程。
+- route 決定 layout 類型。
+- `AppShell` 決定套用哪個 shell layout。
+- layout 專注在骨架與共用框架 UI。
## 命名規則
### 頁面與 page component
-- 直接被 route 載入的檔案放 `views`
-- 負責完整頁面畫面組裝的元件,檔名用 `Page` 前綴
-- page component 不放進 `base`
-
-目前例子:
-
-- [PageLogin.vue](../src/components/PageLogin.vue)
-- [PageIndex.vue](../src/components/PageIndex.vue)
-- [PageMaint.vue](../src/components/PageMaint.vue)
+- 直接被 route 載入的檔案放 `views`。
+- 負責完整頁面畫面組裝的元件,檔名用 `Page` 前綴。
+- page component 優先放 `components/pages`;既有 template 外殼可保留在 `components` 根目錄。
+- page component 不放進 `base`。
### 資料夾命名
-- 多字資料夾一律使用 `kebab-case`
-- 不新增 `snake_case` 或 `PascalCase` 資料夾
+- 多字資料夾一律使用 `kebab-case`。
+- 不新增 `snake_case` 或 `PascalCase` 資料夾。
目前例子:
- `main-layout`
- `master-detail`
+- `page-drivers`
-### domain component 命名
+### component 命名
-- 與特定領域強綁定的元件,優先用領域意圖命名
-- 不要為了抽象而保留含糊的舊前綴
-- 若元件只在 maint 領域使用,就留在 `components/maint`
+- Page component:`PageXxx.vue`
+- Section component:`SectionXxx.vue`
+- Item component:`ItemXxx.vue`
+- Base component:不使用 `Page` / `Section` / `Item` 前綴,直接以功能命名。
## 新增或修改檔案時的判斷準則
1. 這個檔案是否直接被 route 載入?
- - 是:優先放 `views`
+ - 是:優先放 `views`。
2. 這個檔案是否負責某個完整頁面的主畫面組裝?
- - 是:用 `Page` 前綴,放 page component 層,不要塞進 `base`
+ - 是:用 `Page` 前綴,優先放 `components/pages`,不要塞進 `base`。
3. 這段重複的是模板還是流程?
- - 模板:抽元件
- - 流程:抽 composable 或 store
+ - 模板:抽元件。
+ - 流程:抽 composable、page driver、command 或 store。
4. 這個狀態是否跨頁共享,或需要快取 / 全域顯示控制?
- - 是:優先考慮 store
+ - 是:優先考慮 store。
5. 這個邏輯是否在處理 API、token、session、錯誤正規化?
- - 是:放 `services`
-6. 這個元件是否只屬於單一 domain?
- - 是:優先放到該 domain 目錄,例如 `components/maint`
+ - 是:放 `services`。
+6. 這個元件是否只屬於單一 domain 或單一頁面家族?
+ - 是:優先放到該 domain / feature 目錄,例如 `components/maint` 或 `components/login`。
7. 這個抽象是否真的降低重複與理解成本?
- - 否:不要抽
+ - 否:不要抽。
diff --git a/src/views/GUIDE.md b/src/views/GUIDE.md
index 7a6080b..a9ae71f 100644
--- a/src/views/GUIDE.md
+++ b/src/views/GUIDE.md
@@ -26,6 +26,17 @@ const page = useReportsPage()
```
+## Login.vue 開關
+
+`Login.vue` 是登入頁的組合層,登入頁功能開關集中在 view 內宣告,再透過 `PageLogin` / composable 往下傳遞,不在子元件各自決定是否啟用。
+
+- `withCaptcha`:控制驗證碼 UI、captcha API 載入/刷新,以及登入 payload 是否帶 captcha 資料。關閉時不應發出 captcha API,也不應檢查或送出 captcha 欄位。
+- `withAnnouncement`:控制公告 UI、公告 mock data/composable 資料流與公告詳情互動。關閉時公告板、手機公告列與公告對話框資料來源都應停用。
+- `withForgotPassword`:控制忘記密碼連結與事件。關閉時 UI 不顯示,也不應觸發忘記密碼事件。
+- `withRememberAccount`:控制記住帳號 UI 與 localStorage 讀寫。關閉時不顯示 checkbox、不讀寫記住帳號 storage,送出資料固定視為未記住帳號。
+
+新增登入頁選配功能時,優先維持同樣模式:view 宣告開關、composable 負責資料流與 side effect、page/form component 只依 props 呈現 UI 與發出事件。
+
## 子目錄
- `views/maint` 是 maintenance demo route entry。詳見 `src/views/maint/GUIDE.md`。