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 的單元/整合測試,涵蓋驗證、搜尋條件、不可變欄位、唯一性與狀態切換。
返回