# Admin / Client UI 拆分工作計劃 ## 目標 - 在同一個 `MemberCenter.Web` 專案中,將會員端與管理端 UI 明確分區。 - 保持單一登入入口與單一帳號系統。 - 讓具有 `admin` 權限的帳號同時可使用會員功能與管理功能。 - 將目前偏向後台的共用介面,調整為 client-first 的會員中心體驗。 - 補齊會員註冊、Google 第三方登入與訂閱資料銜接流程。 ## 已確認決策 ### 帳號與登入 - `Admin` 與 `Client` 共用同一個登入入口。 - `Admin` 帳號同時也是會員帳號,可使用會員介面功能。 - 不拆成兩套認證系統,不建立獨立 admin login。 ### UI 與導覽 - 會員端為主介面。 - 功能選單採分組方式呈現。 - 一般會員只看到會員功能。 - 具有 `admin` role 的帳號,額外看到 `Admin` 功能分類。 - `Admin` 分類展開後顯示管理功能連結。 - 目前先以 `admin` role 做整包顯示,不先做細權限切分。 ### 未授權存取 - 非 admin 使用者存取 `/admin/*` 時,回應 `404`。 - 不使用 `403` 頁面暴露後台存在。 ## 目標範圍 ### 本次要做 - 調整 `MemberCenter.Web` 路由與結構,將管理端移入 `Areas/Admin`。 - 將現有共用 layout 改為 client-first 導覽。 - 將 admin 功能從全站共用導覽中抽離,改成 role-based 顯示。 - 建立 admin 路由未授權時回 `404` 的處理方式。 - 補上會員註冊、第三方登入與訂閱綁定的工作規劃。 ### 本次不做 - 細粒度權限模型,例如依功能模組拆 `tenant.read`、`audit.read`。 - 獨立的 `AdminWeb` / `ClientWeb` 專案拆分。 - 大幅重做視覺設計。 - API 權限模型重構。 - 註冊確認信寄送實作。 ## 實作策略 ### 策略原則 - 先切 UI 邊界,再保留既有 Identity 與 role policy。 - 先做低風險結構重整,不同時引入細權限與大幅 UI redesign。 - 保持既有 URL 慣例,避免不必要的 route breakage。 ### 預期結構 ```text src/MemberCenter.Web/ ├── Areas/ │ └── Admin/ │ ├── Controllers/ │ └── Views/ ├── Controllers/ # client only ├── Views/ │ ├── Shared/ │ │ ├── _Layout.cshtml # client-first layout │ │ └── ... │ └── ... ``` ## 分階段計劃 ### Phase 0: 會員註冊與帳號銜接規格補齊 狀態:已完成 目標:先將會員建立、第三方登入與訂閱資料綁定的規則固定,避免後續 UI 與 auth 重構互相衝突。 #### 需求規則 - 會員帳號以 `email` 為主要識別。 - `UserName` 強制等於 `Email`。 - 不提供獨立 username。 - 本地註冊完成後,帳號標記為未認證。 - 本階段先不寄送確認信。 - 未認證帳號仍可登入。 - 後續功能完整後,未認證帳號將可被限制部分功能;本階段先保留此狀態與擴充空間。 - 支援 Google 作為第一個第三方登入/註冊 provider。 - Google 第一次登入時,若系統已存在相同 email 的本地帳號,直接 auto-link。 - Google 回傳 email 即使未驗證,仍允許建立帳號或連接既有帳號。 - 使用者若先以本地帳號註冊,之後再以 Google 同 email 登入,應連接到同一個帳號,不建立第二個 user。 - 註冊成功後,若系統中已有相同 email 的訂閱資料,需將相關 `newsletter_subscriptions.user_id` 補上。 - 訂閱綁定時必須保留既有訂閱狀態與偏好,不可覆蓋。 - 訂閱綁定完成後需補一筆 audit log。 - 後續若導入事件,保留發送 `subscription.linked_to_user` 的擴充空間。 #### 子工作 - 已完成:定義本地註冊後的帳號狀態與登入規則。 - 已完成:定義 Google external login / register / auto-link 流程。 - 已完成:定義訂閱資料綁定與 audit log 寫入時機。 - 已完成:將上述規則同步反映到目前的 Web / API 實作階段。 - 已完成:`subscription.linked_to_user` 事件發送。 - 註記:未認證帳號的功能限制屬後續能力擴充,不阻擋本 phase 完成。 - 註記:Google 實際整合驗證仍需提供 Google OAuth 設定,屬外部驗證條件,不阻擋本 phase 完成。 完成條件: - 註冊、Google 登入、同 email 帳號連接、訂閱綁定規則均有明確定義。 - 後續 Phase 1 之後的 UI 與 auth 重構可直接依規則實作。 ### Phase 1: Route 與目錄切分 狀態:已完成 目標:先建立清楚的 UI 邊界。 - 將現有 `Controllers/Admin/*` 移入 `Areas/Admin/Controllers/*`。 - 將現有 `Views/Admin/*` 移入 `Areas/Admin/Views/*`。 - 調整 route 設定,讓 `/admin/*` 由 area route 處理。 - 確認既有 admin URL 可維持不變。 完成條件: - 所有 admin 頁面由 `Areas/Admin` 提供。 - 會員端 controller 不再與 admin controller 混在同一層。 ### Phase 2: Layout 與導覽切分 狀態:已完成 目標:把 UI 改成 client-first,不再全站露出後台功能。 - 重構共用 layout,移除固定顯示的 admin 連結。 - 建立 client-first 功能選單。 - 若使用者具 `admin` role,顯示 `Admin` 功能分類。 - `Admin` 分類底下先列出既有管理功能: - Tenants - Newsletter Lists - Subscriptions - OAuth Clients - Audit Logs - Security - Blacklist 完成條件: - 一般會員不會在主選單看到 admin 連結。 - admin 使用者可從同一套主介面展開進入管理功能。 ### Phase 3: Admin 畫面容器整理 狀態:已完成 目標:讓進入 admin 區後有明確上下文。 - 規劃 admin area 是否使用獨立 layout。 - 若使用獨立 layout,保留回會員區入口。 - 若先共用 layout,至少在 admin 頁面標示目前位於管理區。 建議: - 第一版可先採用共用主殼 + admin 區塊標示。 - 若後續 admin 功能持續增長,再抽 `_AdminLayout`。 目前進度: - 已完成:獨立 `Admin` area layout。 - 已完成:保留回會員區入口。 - 已完成:admin shell 基礎結構整理(top bar、side nav、active state、區域標示)。 - 已完成:補上可替換的基礎樣式 hooks,避免後續設計重做時需要拆 route 或 view 結構。 - 註記:後續若需進一步整理 admin/client 的整體體驗、內容層級、表格與表單版型,視為 UI/UX refinement,不阻擋本 phase 完成。 完成條件: - 使用者進入 admin 頁面時,有清楚的區域辨識。 ### Phase 4: 未授權存取改為 404 狀態:已完成 目標:保留授權檢查,同時隱藏 admin surface。 - 保留 `[Authorize(Policy = "Admin")]`。 - 增加 admin 未授權時的統一處理,避免顯示預設 `403`。 - 確認未登入與已登入但非 admin 的行為符合預期。 已定案: - 未登入進 `/admin/*`:直接回 `404` - 已登入但非 admin 進 `/admin/*`:直接回 `404` 目前進度: - 已完成:保留 `[Authorize(Policy = "Admin")]`。 - 已完成:admin 未授權時不顯示預設 `403`,改為 `404`。 - 已完成:目前實作上,未登入與非 admin 存取 `/admin/*` 均回 `404`。 - 已完成:將「未登入也回 `404`」正式定案並同步到工作計劃。 ### Phase 5: 驗證與文件更新 狀態:已完成 目標:確保重構後行為可驗證、文件一致。 - 驗證會員端主要頁面仍可正常使用。 - 驗證 admin 帳號可以: - 使用會員功能 - 看見 `Admin` 選單 - 進入 admin 各頁 - 驗證非 admin 帳號無法看見 admin 選單,且直接進 admin URL 會得到 `404` - 更新 README / UI 文件中的 web 結構描述 目前進度: - 已完成:`dotnet build MemberCenter.sln -m:1` - 已完成:會員端主要頁面可用性驗證(首頁 / login / register)。 - 已完成:admin 帳號操作驗證(可登入、可進 member profile、可進 admin route)。 - 已完成:一般會員登入驗證(可登入、可進 profile、首頁不顯示 admin 群組)。 - 已完成:非 admin / 未登入情境驗證(匿名打 `/admin/*` 回 `404`)。 - 已完成:計劃文件、README、UI / Flow / Use Case / Design / OpenAPI 相關文件更新。 - 註記:Google 真實 round-trip 驗證需提供 Google OAuth 設定,屬外部條件,不阻擋本 phase 完成。 ## 影響檔案預估 - `src/MemberCenter.Web/Program.cs` - `src/MemberCenter.Web/Views/Shared/_Layout.cshtml` - `src/MemberCenter.Web/Controllers/Admin/*` - `src/MemberCenter.Web/Views/Admin/*` - 新增 `src/MemberCenter.Web/Areas/Admin/...` - 視需要更新 `docs/UI.md` ## 風險與注意事項 - Area 導入後,view 路徑與 route mapping 容易有小錯誤,需要逐頁驗證。 - 若直接共用同一個 layout,需避免 client 與 admin 的語意混亂。 - `404` 偽裝策略要搭配真正的 authorization,不能只靠 route 隱藏。 - 若未登入也直接回 `404`,可能會讓合法 admin 使用者失去登入引導;這點需明確決策。 ## 建議執行順序 1. 先完成 Phase 0,確認註冊、Google 登入與訂閱綁定規則。 2. 再完成 Phase 1,做純結構重整。 3. 接著做 Phase 2,修正選單與角色顯示。 4. 然後決定 Phase 3 要共用 layout 還是抽 admin layout。 5. 再做 Phase 4,補齊 `404` 授權行為。 6. 最後做 Phase 5 的驗證與文件更新。 ## 本次文件用途 這份計劃作為後續逐步實作的工作底稿。後續每一步都應以「單一階段可驗證完成」為原則,避免一次改太多導致 routing、授權與 UI 問題混在一起。 ## 目前總結 - 已完成:Phase 0、Phase 1、Phase 2、Phase 3、Phase 4、Phase 5 - 部分完成:Phase 5