# 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
