FR-148 · 設計文件 · 2026-10-18(D1~D16 全數定案)
關卡是任務裡面的事;BPMN 流程圖一顆方塊一筆任務,不動圖
管理員在系統設定建幾個任務關卡樣板(只是關卡骨架:名稱、說明、順序,不設負責人);PM 在規劃頁替任務選樣板、每一關各派部門+人員(可多人);任務卡上多一條關卡進度,按鈕跟著「你是不是當下那關的人」變(送審/核可/退回),每換一關通知下一關的人;走完最後一關才呼叫既有的「完成任務」讓流程往下走。出廠預設是零關的「無關卡」=現狀,沒設定的客戶什麼都不會變。
狀態:設計定案(D1~D16),待開卡|日期:2026-10-18 討論稿(含四方案比較、被排除選項):
discussion.html|雛形:prototype/index.html開發 branch:三個 repo 目前都在feature/FR-139(開工前 runner 自己git branch --show-current確認,不對就停下問)
🔴 這份是設計決策,不是現況。 內文的行號停在 2026-10-18 定稿當時,實作改動的結果不回頭改寫這裡——現況看實作完成後的 FINAL-SPEC.md。
路徑慣例:BE 路徑相對 compliance-manager-be/;pkg/ 代表 ~/Projects/Jedicogy/module/jedi-python-package/;FE 路徑相對 compliance-manager-fe/。
| 日期 | 變更 | 對應 |
|---|---|---|
| 2026-10-18 | 初版設計定案:D1~D15、資料模型、六卡拆分、端到端驗收 | FR-148 |
| 2026-10-18 | §5.7/D7 改「任務建立時套公司預設」:runner 實查「啟動稽核」在任務做完之後,原設計的掛點不成立;決策者裁 A | CM-2885 |
| 2026-10-18 | 新增 D16 退回只到上一關;§5.4 退回彈窗、§5.6 樣板編輯彈窗改版(Steps 預覽、名稱說明分兩列、關卡表不放開始/結案) | 決策者裁示 |
| 2026-10-18 | 內建零關樣板改名「無關卡」 | 決策者裁示 |
一個任務要經過「交證據 → 主管審 → 顧問審」時,是同一張卡依序交給不同的人,不是三張卡。
現在任務只有「未開始/進行中/已完成」三態。想讓一個任務經過主管、顧問兩道審核,只能在流程圖畫三個方塊——而流程圖的規則是一個方塊=一筆任務(FR-112 定的,證據、留言、問卷、執行紀錄全掛在那一筆上),於是變成三張卡:證據在第一張、主管在第二張看不到證據、顧問在第三張看不到前兩張的留言。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
participant AD as 管理員
participant PM as 專案管理者
participant EX as 執行人(第 1 關)
participant MG as 主管(第 2 關)
participant CS as 顧問(第 3 關)
participant BE as 後端
participant WF as BPMN 引擎(不改)
AD->>BE: 系統設定建樣板「標準三關」
PM->>BE: 規劃頁替任務選樣板(複製一份到任務)+每關派部門/人員
Note over WF: 專案啟動,方塊實體化成進行中(既有)
BE-->>EX: 通知(既有 notify_user_todo_job,收件人=第 1 關)
EX->>BE: 上傳證據、按「送審」
BE->>BE: 目前關卡 1→2、寫歷程
BE-->>MG: 通知「待你處理」
MG->>BE: 看同一張卡的證據與留言,退回到第 1 關+理由
BE->>BE: 目前關卡 2→1、寫歷程
BE-->>EX: 通知「被退回」+理由
EX->>BE: 補證據、再送審
MG->>BE: 核可
BE-->>CS: 通知
CS->>BE: 核可並結案
BE->>WF: complete_job()(既有)
WF->>WF: 下一方塊實體化、通知其執行人(既有)
整案一句話:任務身上帶一份從樣板複製來的關卡清單+每關一組人,同一張卡依序換手,走完最後一關才讓流程往下;出廠預設零關=現狀。
| 卡 | 做什麼 | 產出 | 決策者檢查法 |
|---|---|---|---|
| ① 任務卡關卡進度+送審/核可/退回+歷程 | 任務卡標頭多關卡進度、狀態標籤右邊多時鐘圖示開歷程彈窗、底部按鈕跟著當下那關的人變、每換一關寄信 | 五張新表+任務兩欄的 migration、推進/退回 service 與三支端點、FE 三個子元件 | 對照 雛形頁 1:DEV 手灌一個三關任務,用三個帳號各登入一次走送審→核可→核可並結案,歷程三筆、每步下一關的人收到信;主管退回時執行人收到信且卡回第 1 關 |
| ② 待辦任務頁 | 第 2 關以後的人也看得到任務;多「目前關卡」欄、「待我處理」段 | vw_user_job_queue 併入關卡指派表、待辦查詢加兩欄一條件、FE 欄與段 |
對照 雛形頁 2:主管帳號登入,「待我處理」看得到等他審的那筆;執行人帳號看到被退回的那筆 |
| ③ 系統設定「任務關卡樣板設定」 | 清單+編輯 dialog(版型同專案列表);建/改/刪樣板;內建「無關卡」 | CRUD 端點、能力點、FE 清單頁與 dialog、ui_routes 選單 |
對照 雛形頁 4:新增一個兩關樣板、改順序、設預設,重開頁面還在;「無關卡」刪除鈕是灰的 |
| ④ 規劃頁選樣板+每關指派+套用到其他任務 | 任務表單的「部門+人員」兩格換成一行摘要+「設定」;彈窗內選樣板、每關一組部門→人員、套用到其他任務;開始後樣板鎖、人可改 | 套樣板端點、每關指派端點、批次套用端點、FE 摘要列與彈窗子元件 | 對照 雛形頁 3:選「標準三關」、三關各派人、存檔重開還在;已開始任務換不了樣板但能換人,新加的人(若是當下那關)收到信 |
| ⑤ 啟動預設、退回重開、批次推進、啟動前提醒 | 專案啟動時沒選樣板的任務帶公司預設;管理員退回重開時回第 1 關;批次完成改成推進當下那一關;啟動前軟提醒加「有關卡沒派人」 | 啟動掛點、兩處重開 hook、批次完成改寫、PlanningReadinessChecker 加一項 |
已結案任務退回重開 → 回第 1 關、執行人收到信;待辦勾三筆按批次完成,三筆各前進一關;有關卡沒派人時按啟動會跳確認視窗列出 |
| ⑥ 任務配置 Excel 對齊 | 指派/部門兩欄改為第 1 關;加唯讀「任務關卡」摘要欄;填寫說明加一句 | job_import_service.py、task_guidance_workbook 填寫說明、JobImportDialog.vue 預覽加唯讀欄 |
匯出一份含三關任務的檔,看到摘要欄;改第 1 關的人匯入,第 2、3 關的人不變 |
依賴:① 是地基(表與 service),先做;②③ 只依賴 ①,可平行;④ 依賴 ①③;⑤ 依賴 ①④;⑥ 依賴 ①④。卡的排序以「決策者何時看得到畫面」為準——① 做完就能用 DEV 手灌資料看到任務卡走完整條。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
C1[① 任務卡關卡進度<br/>表+service+任務卡] --> C2[② 待辦任務頁]
C1 --> C3[③ 任務關卡樣板設定]
C3 --> C4[④ 規劃頁選樣板<br/>每關指派]
C4 --> C5[⑤ 啟動預設/退回重開<br/>批次推進/啟動提醒]
C4 --> C6[⑥ 任務配置 Excel]
| # | 定案 | 理由 | 被排除 |
|---|---|---|---|
| D1 | 樣板不設負責人;每關由誰做是 PM 在規劃頁指派,跟現在指派任務人員同一套操作(部門→人員),每關可多人。第 1 關=原本的指派人員 | 樣板是公司層範本、誰做是專案的事;沿用現有操作 | 樣板上填專案角色、跑到那關查角色——多一層間接,PM 看不出某關是誰 |
| D2 | 畫面呈現「開始 → 1 → 2 → … → 結案」,開始/結案只是端點,不存資料、不編號、沒有人與按鈕 | 讓流程看起來完整;零關就是「開始 → 結案」,一眼看得出是直通 | — |
| D3 | 作廢(D1 後不需系統找部門主管) | — | — |
| D4 | 同一關多人時,任一人核可或退回就算數;歷程記是誰 | 全部都要簽=會簽,要多一層「已簽幾個」,第一版不做 | 會簽 |
| D5 | 任務開始後樣板不能換、關卡結構不能改,但每關的人可以改(D15 放寬);系統改樣板不影響已套用的任務(任務拿的是複製品) | 避免「主管正在審、第 2 關被刪」;換人不改結構、常見(請假、換顧問) | 開始後全鎖——沒派齊的關卡會卡死無人能補 |
| D6 | 退回不清證據,執行人在原有證據上補 | 證據本來可以多筆,歷程記退回理由 | 標記「上一輪」證據 |
| D7 | 系統出廠內建零關樣板「無關卡」並設為公司預設(seed migration 寫入;不可刪、不可改名、不可加關)。任務建立時沒選樣板就帶公司預設(三個建立點;不在啟動稽核套,見 §5.7);已在跑的舊專案不回頭套 | 預設=現狀,沒設定的客戶什麼都不會變;管理員自己改預設才會變 | 「標準三關」當預設 |
| D8 | 待辦頁批次完成:推進每筆當下那一關(第 1 關=送審、審核關=核可、零關=完成);只有當下那關有你的任務勾得到;退回仍要逐筆 | 執行人一次交十筆、主管一次核可十筆都常見;批次沒有理由欄 | 審核關不能批次 |
| D9 | 問卷任務第一版不能套樣板,維持問卷自己的審核(待審核/待補充說明、approval_required、is_approver) |
一起併要動 jedi-survey 發版+FE 12 檔 | 一次併 |
| D10 | 資源庫任務範本不預設樣板 | FR-147 剛做完那頁 | — |
| D11 | 樣板建在系統層(帶 tenant_id),各專案在規劃頁自己決定哪些任務套哪一個、可「套用到其他任務」 |
公司建一次、全部專案能選;放系統層或專案層工作量相同 | 專案層——每個新專案要重建 |
| D12 | 不做單一任務微調關卡(加減關、改名);要不同關卡就套不同樣板(不審=零關的「無關卡」) | 微調讓「這個任務走哪套」無從追查 | 任務層微調 |
| D13 | 規劃頁「任務配置」Excel 只管第 1 關:指派人員/參與部門兩欄=第 1 關;加一欄唯讀「任務關卡」摘要;第 2 關以後與樣板不進 Excel | 關數不一,攤成欄會大半空格且欄位會跑;審核關通常固定幾人,彈窗設就夠 | 每關攤成欄 |
| D14 | 改善計畫(POA&M)任務不套樣板,改善計畫頁與其 Excel 不動 | 稽核後才產生、走另一條流程 | — |
| D15 | 啟動前「有關卡沒派人」是軟提醒,併入既有 PlanningReadinessChecker(按確認仍可啟動);搭配 D5 放寬讓開始後還能補人 |
與既有啟動檢查做法一致;硬擋會讓 PM 為一個顧問還沒定就整個專案動不了 | 硬擋 |
| D16 | 退回只能退回上一關,第 1 關不能退;樣板不設退回目標。規則由後端算,存的 back_to_seqs 不採用(舊樣板與進行中任務一併適用) |
每關各勾「可退到哪幾關」設定太複雜,實務上幾乎都是退給上一手 | 每關自訂可退回的關卡 |
用詞:系統設定選單「任務關卡樣板設定」、每筆「任務關卡樣板」、任務卡上那條「關卡進度」、每一站「關卡」。「流程」只留給 BPMN 流程圖。
| 元件 | 現況(2026-10-18 核對) | 本案動作 |
|---|---|---|
任務狀態 JobStatus |
pkg/jedi-flow-engine/jedi_flow_engine/common/enum/job_code.py:TODO/PROCESSING/COMPLETED/CANCEL |
不動。關卡在 PROCESSING 期間換手 |
任務表 compliance.job_executions |
ORM 在 pkg/jedi-flow-engine/jedi_flow_engine/infra/models/job_execution.py;FR-137/FR-140 已加週期、期限欄 |
加 review_step_no、review_template_id 兩欄(ORM 同步改套件,走 path dependency) |
| 完成任務 | api/flow_engine/routes/flow_engine_route.py:42 → workflow_execution_service.complete_job()(:623)把下一方塊實體化並 notify_user_todo_job |
有關卡且未到最後一關時,此端點要擋(否則繞過關卡);推進 service 走到最後一關時由 BE 呼叫它 |
| 批次完成 | app/flow_control/service/job_batch_complete_service.py:43 batch_complete(210 行) |
D8:有關卡的任務改走推進當下那一關 |
| 退回重開 | app/flow_engine/service/job_reopen.py:10 reopen_job_execution(24 行);app/flow_control/service/job_restart_service.py:63 restart_from_first_station(週期重跑) |
兩處結束時把目前關卡重設為第 1 關、寫一筆歷程 |
| 通知 | workflow_execution_service.py:1209 notify_user_todo_job(job_id, assignees=None):只在任務 PROCESSING 時寄;沒給 assignees 就查 task_assignees |
換關時把該關的人當 assignees 傳入;不新開管線 |
| 換人通知 | job_service.py:503 _notify_newly_added_assignees:比對新舊名單,只寄給新加的人 |
每關換人比照:只寄新加的人、且只在該關是當下那關時寄 |
指派表 compliance.task_assignees |
pkg/jedi-task-platform/jedi_task_platform/participant/infra/model/task_assignee.py:is_approver(問卷審查人員專用)、role |
不動。第 1 關=這張表;第 2 關以後另存新表 |
| 🔴 待辦清單 | app/readmodel/service/my_jobs_app_service.py:51 → infra/readmodel/tasks/my_grc_jobs_query.py → view public.vw_user_job_queue(scripts/sql/view/vw_user_job_queue.sql,FROM compliance.task_assignees) |
view 要併入關卡指派表,不然第 2 關以後的人看不到任務 |
| 啟動前檢查 | pkg/jedi-compliance-audit/jedi_compliance_audit/app/service/planning_readiness_checker.py(128 行)兩項軟提醒;接線 di_containers/flow_control/flow_control_containers.py:699;由 oscal_stage_handlers.py LaunchAuditOnCompleteHandler 呼叫,force 放行 |
加第三項「有任務的關卡沒派人」;動 jedi-compliance-audit 套件 |
| 規劃頁任務表單 | FE src/components/grc/planning/AoTaskForm.vue(749 行,接近 800 上限):部門 MultiSelect(:436)→ 人員 MultiSelect 依部門篩(:443,usersInDepts/keepAssigneesInDepts);問卷任務多一排審核者開關(:448) |
非問卷任務的部門+人員兩格換成摘要列+「設定」;彈窗另開子元件 |
| 任務卡 | FE src/components/grc/JobExecutionDrawer.vue(2,344 行,已超標);標頭 JobDrawerHeader |
關卡進度、歷程圖示+彈窗、動作區各開子元件,抽屜只插幾行 |
| 待辦頁 | FE src/views/project/MyTasksView.vue(760 行) |
加欄與段 |
| 任務配置 Excel | app/flow_control/service/job_import_service.py(492 行):前九欄共用(task_guidance_workbook.py)+任務類型/指派人員/參與部門/設備;JobImportDialog.vue(443 行) |
D13 |
| 系統設定頁慣例 | FE src/views/ 下 notify-config、system-menu-manage 等;版型參考 src/views/project/ProjectListView.vue(標題列+搜尋+表格卡+編輯 dialog) |
新頁照專案列表版型 |
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
erDiagram
review_step_templates ||--o{ review_step_template_items : "一個樣板多關"
job_executions ||--o{ job_review_steps : "套樣板時複製"
job_review_steps ||--o{ job_review_step_assignees : "每關的人(可多人)"
job_executions ||--o{ job_review_step_logs : "每次推進/退回"
review_step_templates {
int id PK
string uid
int tenant_id "RLS"
string name
text description
bool is_default "公司預設,每租戶最多一筆"
bool is_builtin "內建無關卡"
}
review_step_template_items {
int id PK
int template_id FK
int seq "1 起算"
string name
text description
int[] back_to_seqs "退回目標,固定為上一關(D16)"
}
job_executions {
int review_step_no "目前第幾關;NULL=零關"
int review_template_id "來源樣板,只記錄"
}
job_review_steps {
int id PK
int job_execution_id FK
int seq "1 起算"
string name
text description
int[] back_to_seqs
}
job_review_step_assignees {
int job_execution_id FK
int seq "2 起算;第 1 關用 task_assignees"
int user_id
int org_unit_id "部門,可空"
}
job_review_step_logs {
int id PK
int job_execution_id FK
int seq "在哪一關"
string action "submit / approve / reject / reopen"
int to_seq "退回到哪關"
int user_id
text note
timestamptz created_at
}
要點:
review_step_*(程式識別),中文介面叫「任務關卡」。全部放 compliance schema。review_step_no 為 NULL=零關(直通),行為與現況完全相同;非 NULL 時 1..N 是目前所在關卡,走完最後一關核可時呼叫 complete_job、欄位停在 N。task_assignees(原指派人員,含問卷的 is_approver 不動);第 2 關以後存 job_review_step_assignees。所以零關任務、問卷任務完全不碰新表。job_execution_org_unit);第 2 關以後的部門存在 job_review_step_assignees.org_unit_id(同一關選多部門時,每個「人×部門」一列;只選部門沒選人不算已指派)。is_default:每租戶最多一筆,用部分唯一索引 WHERE is_default 保證。內建「無關卡」由 seed migration 為每個租戶寫一筆並設為預設;is_builtin=true 的不可刪、不可改名、不可加關。review_step_templates 帶 tenant_id,FOR ALL 條件「超管或 app_tenant_allowed_for_session(tenant_id)」;其餘四張無租戶欄,跟隨父表(review_step_template_items 跟隨樣板、三張 job_* 跟隨 job_executions 所屬專案),並加進 test/security/database/test_project_scoped_tables_rls.py 清單。每張表 GRANT ... TO cm_app + sequence 權限。infra/;任務三張跟 job_executions 同層(主專案 infra/flow_control/,不放套件——套件只加兩個欄位,避免把關卡業務塞進流程引擎套件)。新開 app/flow_control/service/review_step_service.py(不塞進已近千行的既有 service):
| 方法 | 誰能叫 | 做什麼 |
|---|---|---|
submit(job_uid) |
第 1 關的人(task_assignees) |
目前關卡 1→2;寫歷程 submit;通知第 2 關的人 |
approve(job_uid, note) |
當下那關的人 | 若不是最後一關:關卡 +1、寫歷程、通知下一關;若是最後一關:寫歷程 approve、呼叫 workflow_execution_service.complete_job() |
reject(job_uid, to_seq, note) |
當下那關的人;note 必填;to_seq 必須在該關 back_to_seqs 內 |
關卡改成 to_seq、寫歷程 reject、通知 to_seq 那關的人 |
reset_to_first(job_execution) |
內部(重開 hook 呼叫) | 關卡回 1、寫歷程 reopen;caller 在 @transaction 內 |
規則:
assert_project_participant;再判「你是否在當下那關的名單」,不是就 ForbiddenError(新錯誤碼 GRC_403070 起)。submit/approve/reject → PreconditionFailedError(GRC_412070 起)。WHERE review_step_no = :expected),更新 0 列就回 ConflictError(GRC_409048 起),避免兩人同時核可推進兩格。complete_job 進入點對「有關卡且 review_step_no 不是最後一關」的任務拋錯;推進 service 自己呼叫時帶內部旗標放行。否則前端舊按鈕或批次完成能繞過關卡。notify_user_todo_job(job_id, assignees=<該關的人>);文案沿用既有「待你處理」,被退回時多帶理由(若既有通知不支援理由欄,第一版只寄既有文案,理由看歷程)。端點(api/flow_control/routes/ 新檔):
POST /grc/jobs/<job_uid>/review-steps/submitPOST /grc/jobs/<job_uid>/review-steps/approve body {note}POST /grc/jobs/<job_uid>/review-steps/reject body {to_seq, note}GET /grc/jobs/<job_uid>/review-steps → {template_name, current_seq, steps:[{seq, name, description, back_to_seqs, assignees:[{user_uid, name, dept_name}]}], logs:[{created_at, seq, step_name, action, to_seq, user_name, note}]}(歷程的人名照「審計欄位回傳規範」在 app service 批次轉 nickname)JobExecutionDrawer.vue 已超標,只插三行:在 JobDrawerHeader 下掛 <JobReviewStepBar>;標頭狀態標籤右邊掛時鐘圖示按鈕(角標筆數),點開 <JobReviewHistoryDialog>;描述區上方掛 <JobReviewActionBox>。底部原「完成任務」按鈕:有關卡時換成 <JobReviewActions>(送審/核可/核可並結案/退回)。vw_user_job_queue 改為 task_assignees UNION job_review_step_assignees 兩個來源(後者 user_id 帶出同欄位、is_approver=false),並多帶 review_step_no、review_step_name、review_step_count、is_current_step_assignee(這位使用者是否在當下那關)。改 view 時整支 CREATE OR REPLACE、欄位只加在尾端(FR-140 先例 scripts/sql/2026-10-15-fr140-job-executions-due-at.sql:111 的 GRANT 要重下)。job_status = PROCESSING AND is_current_step_assignee(零關任務:在 task_assignees 即算)。MyTasksView.vue:狀態欄右邊加「目前關卡」(2/3 主管審核,待你處理時橘色小標);分段加「待我處理(N)」放最前。review_step_template.manage(宣告在 core/host_capabilities.py,跑 scripts/deliverables/gen_permission_matrix.py 產 FE 常數);列表 GET 只要登入(規劃頁下拉要讀)。寫入是全站共用設定,另過 require_tenant_hq()。ui_routes 一列+route_capabilities 一顆(seed migration),選單掛在系統設定底下。ProjectListView.vue:標題列(名稱+「共 N 筆樣板」)+右邊「新增任務關卡樣板」;搜尋框+重設;表格欄:樣板名稱(內建者加「系統內建」標)/說明/關卡數/公司預設/已套用任務數/操作(鉛筆、垃圾桶)。不放關卡預覽。點一列或新增開編輯 dialog,表單由上而下單欄排列:樣板名稱、說明(多行)、公司預設勾選、關卡預覽(PrimeVue Steps,開始/結案用圖示、中間關卡編號對齊關卡表)、關卡表(只列實際關卡:編號、名稱、說明、上下移、刪;不列開始/結案,沒有退回設定)。AoTaskForm.vue 只剩 51 行額度:非問卷任務的「部門+人員」兩格整段換成 <TaskReviewStepSummary>(一行:樣板名、關數、「N 關已指派、M 關未指派 ⚠」+「設定」按鈕;已開始顯示「檢視/換人」);問卷任務維持原兩格與審核者開關。
彈窗 <TaskReviewStepDialog>:樣板下拉(含零關)→ 關卡預覽 → 每關一列「部門 MultiSelect → 人員 MultiSelect(依部門篩,重用 usersInDepts/keepAssigneesInDepts)」,第 1 關標「=原本的指派人員」;零關只有一列;左下「套用到其他任務」、右下取消/儲存。
換樣板:同位置已派的人保留,多出來的關空著;少掉的關的人刪除。
任務開始後:樣板下拉與關卡結構唯讀,人仍可改(D5)。
換人時的通知(比照現況:notify_user_todo_job 只在任務進行中才寄;job_service.py:355 先記舊名單、:503 _notify_newly_added_assignees 只寄新加的人):
| 換人的是哪一關 | 寄給誰 |
|---|---|
| 任務還沒啟動 | 不寄;啟動時寄給第 1 關當下的名單 |
| 任務進行中,換當下那關 | 只寄新加的人 |
| 任務進行中,換還沒走到的關 | 不寄;走到那關時寄給那時的名單 |
| 任務進行中,換已走過的關 | 不寄;之後被退回到那關時寄給那關當下的名單 |
例:第 2 關原本派雷門,雷門離職改派阿好——不論何時改,信只會在輪到第 2 關時寄給阿好。被移除的人不收任何通知(現況也沒有),第一版不做移除通知。
套用到其他任務:比照流程圖「套用到其他任務」動線(flow_apply_to_tasks_service.py 的候選列法:同專案同輪),只列未開始、非問卷任務;套的是樣板(人保留同位置,新關空著)。
端點:PUT /grc/jobs/<job_uid>/review-steps(body {template_uid, steps_assignees:[{seq, dept_uids, user_uids}]})、POST /grc/jobs/review-steps/apply(body {template_uid, job_uids})。守門:專案 manager。
prep_job_generation_service.py)、規劃頁新增任務(job_service.create_job)、覆核輪產生任務(reverify_inheritance_service)。只對「非問卷、還沒有 job_review_steps」的任務套;公司預設是零關就什麼都不做;舊專案不回頭套。不在「啟動稽核」套:啟動稽核是規劃階段結束、任務都做完才按的(它的既有前置就是「證據任務未完成」提醒),那時套關卡沒意義。排除 B「PM 按開始執行任務才套」:套上時第 2 關以後都沒人、一送審就卡住,且要改任務平台的啟動掛鉤。reopen_job_execution 與 restart_from_first_station 結束時,對有關卡的任務呼叫 review_step_service.reset_to_first。job_batch_complete_service.batch_complete 對有關卡的任務改呼叫 submit/approve(當下那關有你才處理,否則計入 skipped 並回原因)。PlanningReadinessChecker 加 WARN_REVIEW_STEPS_UNASSIGNED = "review_steps_unassigned",context {count, jobs:[{uid, name, missing_seqs}]};FE 確認視窗的提醒清單加一種文案(i18n key 同 code)。檢查要讀主專案的新表 → 用注入的查詢介面,不讓套件 import 主專案。EXTRA_COLUMNS 尾端加一欄「任務關卡」(唯讀灰底),值例:「標準三關(3 關,2 關已指派)」/「無關卡」;「指派人員」「參與部門」欄標頭不改字(相容舊檔),填寫說明頁加一句「多關卡任務:指派人員/參與部門是第 1 關(執行人);審核關卡的人員請到規劃頁設定」。task_assignees 的邏輯不變;新欄不讀;舊檔沒有這欄照樣能匯入(欄位對應依位置,新欄放最後)。任務已開始時換第 1 關的人照舊放行。JobImportDialog.vue 預覽表加唯讀欄。| 卡 | 範圍 | 依賴 | 驗收 |
|---|---|---|---|
| ① 地基+任務卡 | migration(五表兩欄、RLS、GRANT、內建樣板 seed)、ORM(套件兩欄+主專案新表)、review_step_service、四支端點、既有完成端點擋關卡、FE 任務卡三個子元件 |
— | DEV 手灌一個三關任務,三帳號走完含退回;既有完成端點對有關卡任務被擋;零關任務行為不變 |
| ② 待辦頁 | vw_user_job_queue 改寫、待辦查詢、FE 欄與段 |
① | 第 2 關的人在待辦看得到;「待我處理」正確;同人兩關不重複 |
| ③ 樣板設定頁 | CRUD 端點、能力點、ui_routes、FE 清單+dialog |
① | 建/改/刪/設預設;內建不可刪 |
| ④ 規劃頁 | 套樣板/每關指派/套用到其他任務端點、FE 摘要列+彈窗;開始後可換人並通知 | ①③ | 對照雛形頁 3 |
| ⑤ 啟動/重開/批次/提醒 | 啟動帶預設、兩處重開 hook、批次完成、PlanningReadinessChecker(動 jedi-compliance-audit) |
①④ | 見 §2 表 |
| ⑥ 任務配置 Excel | 匯出欄、填寫說明、匯入預覽 | ①④ | 見 §2 表 |
套件異動:① 動 jedi-flow-engine(job_executions 兩欄 ORM)、⑤ 動 jedi-compliance-audit(readiness checker)。都走 path dependency(pyproject.toml 已是 path 形式),不發版;發版時機等決策者。
reopen。回歸範圍:既有完成任務、批次完成、退回重開、週期重跑、待辦清單、任務配置 Excel 匯入匯出、啟動稽核。