專案

一般

配置概況

Feature #1442

是由 陳國瑋 於 約 1 個月 前更新

## 
 h2. 目標 

 新增 CourseProfile 後台管理 API,讓 `administrator` administrator 維護「療程項目」主檔;後端完成後交由 FE 實作 UI。 

 CourseProfile 是療程類型/主檔,Course 是學員實際建立的療程,關係為: 

 - `hm_course.pid 
 * hm_course.pid → hm_course_profile.pid`(邏輯 hm_course_profile.pid(邏輯 1:N,目前無實體 FK) 
 - * Booking 目前以 `hm_booking.booking_item` hm_booking.booking_item 儲存 `CourseProfile.name`,無 CourseProfile.name,無 FK 

 本工作以 staging 驗證與開發,不操作 production。 

 ## h2. 已確認的 domain rule 

 - `CourseProfile.name` * CourseProfile.name 建立後永久不可修改。 
 - `name` * name 全系統永久唯一,包含停用資料;停用後也不可重複使用名稱。 
 - `has_diary`、`has_satisfaction`、`has_post_event_card` * has_diary、has_satisfaction、has_post_event_card 建立後不可修改。 
 - * 建立後可修改欄位只有 `description`、`enabled`。 description、enabled。 
 - * 不提供實體刪除;只能啟用/停用。 
 - * 新建 CourseProfile 一律為 `enabled=false`,後續由管理員手動啟用。 enabled=false,後續由管理員手動啟用。 
 - `enabled=false` * enabled=false 只阻止未來建立 Course/Booking 時被選取;既有 Course、Booking、歷史資料、日誌、提醒及排程行為均不受影響。 
 - `has_diary=false` * has_diary=false 仍可建立 Course;它是功能能力,不是可建立條件。 
 - `has_satisfaction`、`has_post_event_card` * has_satisfaction、has_post_event_card 目前沒有程式行為,但必須可於建立時設定,供後續功能使用。 
 - `description` * description 非必填、建立後可修改;空白內容正規化為 `null`。 null。 
 - * 權限只提供 `administrator` administrator role。 

 ## h2. 名稱驗證 

 - * 必填,儲存前 trim 前後空白。 
 - * 最長 255 字元。 
 - * 不限制中文、英文、數字或符號;保留內部空白。 
 - * API 驗證唯一性,並新增 DB unique index 雙重保護。 
 - * 唯一性包含 `enabled=false` enabled=false 資料,依現有 DB collation 判斷。 
 - * 重複時回傳可讓 FE 對應到 `name` name 欄位的 validation error。 
 - * 更新 API 不接受 `name` name 與三個功能旗標,不能只依 FE disabled 防護。 

 ## h2. API contract 

 ### h3. 1. 搜尋 

 `POST /api/admin/course/profile/search` POST /api/admin/course/profile/search 

 可選搜尋條件: 

 ```json 
 <pre> 
 { 
   "page": 1, 
   "size": 10, 
   "sidx": [], 
   "sord": [], 
   "keyword": "選填", 
   "enabled": true, 
   "hasDiary": true, 
   "hasSatisfaction": false, 
   "hasPostEventCard": true 
 } 
 ``` </pre> 

 規則: 

 - `keyword` 
 * keyword 對 `name`、`description` name、description 做 OR 模糊搜尋。 
 - `enabled` * enabled 與三個旗標皆為 optional Boolean。 
 - * 未選擇條件時,request 不得帶該 property;不是傳「全部」。 
 - `true` * true 與 `false` false 都是有效搜尋值,FE 不可用 truthy 判斷導致 `false` false 被省略。 
 - * SS3A NativeSearch 欄位為 `null` null 時不產生 SQL condition。 
 - * 預設 `create_time DESC`;支援既有 create_time DESC;支援既有 Datatable 分頁/排序。 
 - * Page content 至少回傳 `id`、`name`、`hasDiary`、`hasSatisfaction`、`hasPostEventCard`、`enabled`。 id、name、hasDiary、hasSatisfaction、hasPostEventCard、enabled。 

 ### h3. 2. 取得單筆 

 `GET /api/admin/course/profile/info/{id}` GET /api/admin/course/profile/info/{id} 

 回傳完整 CourseProfile。FE 編輯頁將 `name` name 與三個旗標顯示為唯讀,只可編輯 `description`、`enabled`。 description、enabled。 

 ### h3. 3. 建立 

 `POST /api/admin/course/profile/create` POST /api/admin/course/profile/create 

 ```json <pre> 
 { 
   "name": "必填", 
   "description": "選填", 
   "hasDiary": true, 
   "hasSatisfaction": false, 
   "hasPostEventCard": false 
 } 
 ``` </pre> 

 規則: 

 - 
 * 三個旗標皆為 required Boolean,建立時必須明確傳 `true` true 或 `false`。 false。 
 - `enabled` * enabled 不由 FE 傳入;後端固定建立為 `false`。 false。 
 - * 建立前 FE 會二次確認 `name` name 與三個不可變旗標。 
 - `description` * description 空白轉 `null`。 null。 

 ### h3. 4. 更新 

 `POST /api/admin/course/profile/update` POST /api/admin/course/profile/update 

 ```json <pre> 
 { 
   "id": "Pxxxxxxx", 
   "description": "選填", 
   "enabled": true 
 } 
 ``` </pre> 

 規則: 

 - 
 * 只允許更新 `description`、`enabled`。 description、enabled。 
 - `name`、`hasDiary`、`hasSatisfaction`、`hasPostEventCard` * name、hasDiary、hasSatisfaction、hasPostEventCard 不可出現在 update DTO。 
 - `description` * description 與 `enabled` enabled 在同一 transaction 更新。 
 - * 若 `enabled` enabled 有變更,FE 必須先取得 impact 並確認;若只改 `description` description 可直接更新。 

 ### h3. 5. 狀態影響資訊 

 `GET /api/admin/course/profile/status/impact/{id}` GET /api/admin/course/profile/status/impact/{id} 

 回傳: 

 ```json 
 <pre> 
 { 
   "id": "Pxxxxxxx", 
   "name": "療程名稱", 
   "enabled": true, 
   "courseCount": 123, 
   "bookingCount": 45 
 } 
 ``` </pre> 

 計數規則: 

 - `courseCount`:`hm_course.pid 
 * courseCount:hm_course.pid = CourseProfile.pid` CourseProfile.pid 的歷史總數,包含所有 Course status。 
 - `bookingCount`:`hm_booking.booking_item * bookingCount:hm_booking.booking_item = CourseProfile.name` CourseProfile.name 的歷史總數,包含所有 Booking status。 
 - * 此 API 於列表 Switch 或編輯頁變更 `enabled` enabled 前呼叫。 
 - * 統計獨立查詢,不放入列表 search,避免每頁資料都執行聚合。 

 ### h3. 6. 列表狀態切換 

 `POST /api/admin/course/profile/status/switch` POST /api/admin/course/profile/status/switch 

 沿用既有 `ReqSwitchStatus`: 

 ```json ReqSwitchStatus: 
 <pre> 
 { 
   "id": "Pxxxxxxx", 
   "newStatus": false 
 } 
 ``` </pre> 

 FE 先呼叫 impact,顯示名稱、Course/Booking 歷史總數與影響說明;管理員確認後才呼叫 switch。取消時不得改變畫面狀態。 

 不提供 delete API。 

 ## h2. DB/SS3A 

 - `hm_course_profile.name` * hm_course_profile.name 新增 unique index;migration 前先檢查重複與空值資料。 
 - * 不新增 `bookable`、`course_creatable` bookable、course_creatable 等欄位,維持現有 `enabled` enabled 單一邏輯。 
 - * 新增 SS3A function、i18n、API mapping 與 role mapping。 
 - * 選單位於 Common Lists,名稱「療程項目管理」。 
 - * 建議 function IDs: 
   - `course_profile_mgmt` 
   - `course_profile_mgmt_list` 
   - `course_profile_mgmt_create` 
   - `course_profile_mgmt_edit` 
 - ** course_profile_mgmt 
 ** course_profile_mgmt_list 
 ** course_profile_mgmt_create 
 ** course_profile_mgmt_edit 
 * 不建立 delete function。 
 - * 上述 function 只 mapping 給 `administrator`。 administrator。 
 - * impact 與 `status/switch` status/switch 歸 `course_profile_mgmt_edit` course_profile_mgmt_edit 權限。 

 ## h2. FE handoff requirement(本 ticket 不實作 FE) 

 - * 列表沿用既有 SectionTitle、WrapperTable、Datatable、ActionButton、Switch 與搜尋元件。 
 - * 列表欄位:ItemId、名稱、日誌、滿意度、關懷卡、狀態、編輯操作。 
 - * 不在列表顯示 Course/Booking 數量;只在狀態確認視窗顯示。 
 - * 不顯示刪除操作。 
 - 搜尋:`keyword`、`enabled`、三個旗標。Boolean * 搜尋:keyword、enabled、三個旗標。Boolean 選項只有「有/無」;未選擇就不帶 request property。 
 - 新增頁:`name`、`description`、三個旗標;建立前二次確認;建立結果固定停用。 * 新增頁:name、description、三個旗標;建立前二次確認;建立結果固定停用。 
 - 編輯頁:`name` 與三個旗標唯讀;`description`、`enabled` * 編輯頁:name 與三個旗標唯讀;description、enabled 可修改。 
 - * 列表 Switch 與編輯頁修改 `enabled` enabled 都必須顯示 impact 確認視窗。 
 - * 啟用提示:啟用後會出現在新建 Course 與 Booking 的選單。 
 - * 停用提示:停用後不再出現在新建 Course 與 Booking 的選單;既有資料與流程不受影響。 

 ## h2. 驗收條件 

 - * 僅 `administrator` administrator 能存取管理 API 與選單 function。 
 - * 可搜尋、分頁、排序 CourseProfile;optional Boolean 未帶時不產生條件,`false` 未帶時不產生條件,false 可正確搜尋。 
 - * 新增時 `enabled` 固定為 `false`;`name` enabled 固定 false;name 與三個旗標建立後無法由 API 修改。 
 - * 相同名稱(含停用資料)無法再次建立;併發建立亦由 DB unique index 阻擋。 
 - * 更新只影響 `description`、`enabled`。 description、enabled。 
 - * 狀態 impact 回傳正確歷史總數。 
 - * 停用後不再出現在既有 Course/Booking 建立選單;既有 Course、Booking 及後續歷史行為不受影響。 
 - * 無 delete API/delete function。 
 - * 補齊 service、repository、controller 的單元/整合測試,涵蓋驗證、搜尋條件、不可變欄位、唯一性與狀態切換。 

返回