FR-160 · Project Role by Stage & Feature — 需求討論稿 · 2026-10-22 · 待決策者裁 D1–D8
系統權限縮成模組開關;專案角色照流程圖勾站、照畫面勾功能
FR-155 做完後,專案角色頁列的 13 顆權限是從程式檢查點倒推出來的,管理員看不出「專案稽核人員要勾哪幾顆」;AI 自動分類、問卷、系統安全計畫這些塞進專案頁的功能又只住在系統權限,專案角色管不到;同一個動作要在系統頁和專案頁各勾一次。本案定一條分層判準——動作有沒有「專案」這個對象——系統角色頁縮成「每模組一顆可使用+沒有專案對象的動作」;專案角色頁改成三區:流程站職責(照流程圖一站一勾)、專案內功能(含 AI 分類、問卷、SSP)、專案管理;流程設計器的「主要角色」改成從角色表反查,不再手選。
我在專案權限那邊,要讓 user 可以知道說噢我今天專案稽核人員要給他哪些?現在看起來都是一堆不相干的權限很詭異。 每一站的權限點不同專案角色要怎麼設定?然後怎麼跟流程那邊的設定結合?發現當初最後一個流程設定設計得很潦草。 各個功能裡面的功能點也要被納進來,像是能不能用 AI 自動分類等等。 — 決策者
| # | 根因 | 證據 |
|---|---|---|
| ① | 專案角色的 13 顆權限是照程式檢查點切的,不是照流程站切的。跟流程圖對得上的只有 4 顆(稽核判定、審閱、管理改善計畫、推進任一階段),其餘 9 顆是專案管理類 | common/authz/project.py、infra/readmodel/ 8 支 SQL、5 套件呼叫端的 proj.* 分布 |
| ② | 塞進專案頁的其他模組功能,權限全住在系統層,專案角色管不到:AI 自動分類(evidence.classification.* 5 顆)、問卷(survey.* 5 顆)、SSP 編輯匯入(oscal.ssp.*)、資源庫更新(oscal.resource-library.*,專案頁 20 處按鈕)、檢測結果、風險 |
FE 專案頁 v-can="CAP.*" 盤點:GRC_JOB_UPDATE 30 處、OSCAL_RESOURCE_LIBRARY_UPDATE 20、SURVEY_SURVEY_UPDATE 17、EVIDENCE_CLASSIFICATION_* 13 |
| ③ | 同一個動作掛兩道門且兩道幾乎重複:後端每個專案內寫入都是「系統 grc.* 過了 → 再問專案 proj.*」;出貨系統角色「稽核主管」是 grc.*.* 全開,「稽核員」「一般成員」也開了任務、稽核、報告的讀寫,系統層那道門幾乎人人都有,真正擋人的是專案層,但畫面上兩邊字一樣 |
api/ 與套件 require_capability("grc.*") 共 200 餘處;resources/roles/shipped-roles.json |
另有兩個實查發現,與設計直接相關:
assert_round_phase(r, {"auditing"}) 回 412),改善計畫里程碑只能在缺失改善站({"remediation"})。「站」已經是真正的工作單位,權限只是多問「你是不是負責這站的人」。task_assignees、審閱站看 job_review_step_assignees、缺失改善站的里程碑表有 assignee_user_id(DEV 18 筆有指派)但結案時沒去看它。角色真正在管的只有「能不能推進這一站」與「稽核站誰能填結果」。看這個動作有沒有「專案」這個對象。 問得出「哪個專案」→ 專案層;問不出 → 系統層。
程式面可機械判定:後端檢查點有先 resolve「這筆資料屬於哪個專案」的就是專案層,沒有的就是系統層。可寫守衛測試驗證,不靠人判斷。
一句話:先用判準把 238 顆系統權限逐顆分邊定稿(C.1),再改資料與升級換算(C.2),把專案內功能點補上專案層守門(C.3),最後三個畫面(C.4)。
| 階段 | 做什麼(白話) | 產出 | 完成怎麼判定(決策者可親手檢查) | 依賴 |
|---|---|---|---|---|
| C.1 分邊定稿 | 238 顆系統權限逐顆套判準:留系統層/併成模組開關/搬到專案層;專案內每個功能點對到一顆專案權限;六個流程站各對到哪幾顆 | inventory/c1-capability-split.md(三張表) |
打開表:每顆都有「系統/專案」結論與一句理由;邊界案例(資源庫、分類設定檔、風險)各有明確歸屬 | D1–D4 |
| C.2 資料與升級 | 系統層新增「可使用 X」每模組一顆、刪併細顆;專案層新增約 15~20 顆;每租戶既有系統角色自動換算(原有任一細顆 → 給模組開關;原只有 read → 給「專案內只能看」);四個範例專案角色改成站+功能的組合 | migration、seed、真實舊庫排練紀錄 | 真實舊庫升級後,用舊帳號登入,選單與專案內按鈕與升級前一模一樣 | C.1 |
| C.3 守門補齊 | 專案內功能點(AI 分類、問卷、SSP、報告、風險…)後端補「專案層也要過」;被指派人那條路補齊(任務、關卡、里程碑);系統層細顆的檢查改成模組開關 | 約 25 個檢查點改動,橫跨 5 套件 | 建一個只勾「稽核」站的專案角色指派給某人:他能填稽核結果,但按 AI 自動分類回 403;把「AI 自動分類」勾上立刻能按 | C.2、D5 |
| C.4 畫面 | 專案角色頁三區(流程站、專案內功能、專案管理)+右側「能做什麼」預覽;系統角色頁改成模組開關+公司層動作;流程設計器「主要角色」改唯讀反查 | FE 三頁 | 對照雛形三頁;建「專案稽核人員」只勾兩站,進專案看到的按鈕正好是那兩站的 | C.3、D6–D8 |
C.1→C.2→C.3→C.4 照順序。
✅ 決策者 2026-10-22 已拍板
D1 系統層最後長什麼樣
套判準後,系統層剩兩類:
| 類 | 內容 | 顆數 |
|---|---|---|
| 模組開關 | grc.use(專案稽核)、evidence.use(證據分類)、survey.use(問卷)、oscal.ssp.use(系統安全計畫)、detection.use、asset.use、ai.use、workspace.use |
8 |
| 沒有專案對象的動作 | 建專案 grc.project.create、刪專案 grc.project.delete、流程範本 flow.template.*、審閱關卡範本 grc.review-step-template.manage、RACI 預設 grc.raci.manage、公司層風險總表 grc.risk.*、治理總覽 grc.governance.*、合規框架 oscal.framework.*、資源庫 oscal.resource-library.*、分類設定檔 evidence.classification-profile.*、雲端整合 evidence.cloud-integration.*、檢測設定(plugin/profile/agent/scan-zone)、資產、AI 設定、系統設定、組織與存取、原廠平台 |
約 110 |
從 238 縮到約 120,拿掉的全是「專案內的讀寫增刪細顆」(grc.job.*、grc.audit.*、grc.job-evidence.*、grc.job-comment.*、grc.summary-report.*、grc.project.read/update/assign、evidence.classification.*、survey.*、oscal.ssp.*、detection.source-scan.execute/export)。
建議照上表。另加一顆 grc.readonly「專案內只能看」:讓管理員仍可把某人設成全公司唯讀,不必逐專案設瀏覽者。升級時原本只有 grc.*.read 的角色自動拿到它。
D2 專案層「流程站」怎麼表示
選項:
proj.stage.<code>:proj.stage.planning、proj.stage.ap_authoring、proj.stage.audit、proj.stage.review、proj.stage.poam、proj.stage.closing,勾了=做這站的事+推進這站。站的動作(填結果、建改善計畫)後端改查對應站的顆。建議 (a):站就是工作單位,權限名對到站,流程設計器才能反查。stage_objects 表已是資料驅動,新加站就新加一顆。
D3 「推進這一站」與「做這站的事」要不要分開
例:有客戶要「稽核員填結果,但只有稽核主管能按推進」。
建議 (a),有客戶要再加。「推進任何階段」這顆仍保留給負責人。
D4 專案內功能點定稿
照「畫面上的功能」分組,不照程式模組。草案:
| 分組 | 顆 | 白話 |
|---|---|---|
| 任務 | proj.job.manage |
建立、指派、匯入、代成員完成、催辦 |
| 佐證 | proj.evidence.upload、proj.evidence.classify、proj.evidence.manage |
上傳佐證/跑 AI 自動分類與確認結果/刪除與批次操作 |
| 問卷 | proj.survey.design、proj.survey.publish |
設計問卷/發布問卷(填答走被指派人) |
| 系統安全計畫 | proj.ssp.update、proj.ssp.import |
編輯/匯入匯出 |
| 評估計畫 | proj.ap.import |
匯入匯出評估計畫 |
| 報告 | proj.report.manage、proj.report.read |
建立與發布/檢視匯出 |
| 風險 | proj.risk.manage |
專案內風險評估 |
| 檢測 | proj.detection.read |
看檢測結果 |
| 專案管理 | proj.project.update、proj.participant.manage、proj.round.manage、proj.stage.advance-any |
設定/成員/輪次/推進任何階段 |
建議照上表,C.1 盤點時逐顆對到後端檢查點,缺的補、沒人用的刪。
D5 「被指派的人」這條路
任務(task_assignees)、審閱關卡(job_review_step_assignees)已經是「被指派人 ∪ 有管理權限的人」;改善計畫里程碑有 assignee_user_id 但結案沒看它。
建議 (a),寫成一條通則進 common/authz/__init__.py 決策表。
D6 流程設計器的「主要角色」欄
proj.stage.<code>,main_role 欄不再讓人選。建議 (a):決策者原話「流程那邊的設定要跟角色結合」。範本上不存角色、只存站,角色改了流程不用改。
D7 專案角色頁右側「能做什麼」預覽
勾完即時顯示:能推哪幾站(照流程圖順序)、進專案會看到哪些按鈕、會收哪些通知。
建議 (a),這是「看不出勾了能幹嘛」的直接解法。
D8 範例專案角色重新定義
| 範例角色 | 流程站 | 專案內功能 | 管理 |
|---|---|---|---|
| 負責人(預設) | 全部 | 全部 | 全部 |
| 稽核員 | 稽核計畫填寫、稽核 | 佐證上傳、AI 分類、評估計畫匯入、報告檢視 | — |
| 審核者 | 審閱 | — | — |
| 瀏覽者 | — | 報告檢視 | — |
建議照上表;「專案稽核人員」就是稽核員,管理員一眼看得出勾了兩站。
三頁雛形在 prototype/index.html。
| 頁 | 新增/改變 |
|---|---|
| 1 專案角色詳情 | 三區:流程職責(照流程圖列六站,一站一勾,站名旁寫「勾了能做什麼」)、專案內功能(任務/佐證/問卷/SSP/評估計畫/報告/風險/檢測)、專案管理;右側「這個角色能做什麼」預覽 |
| 2 系統角色詳情(縮併後) | 「權限」區改成兩段:模組開關(8 顆)、公司層動作(照模組分組);專案內細顆消失 |
| 3 流程設計器 | 任務節點「主要角色」改唯讀:「負責此站的角色:稽核員、資深稽核員」,旁邊連去角色頁 |
| 功能 | 歸屬 | 理由 |
|---|---|---|
| 資源庫更新(專案頁有 20 處按鈕) | 系統層 | 資源庫不屬於任何專案;專案頁上的按鈕是在改共用範本 |
| AI 分類設定檔 | 系統層 | 設定檔全公司共用 |
| 在專案裡跑 AI 分類 | 專案層 proj.evidence.classify |
問得出哪個專案 |
| 公司層風險總表 | 系統層 grc.risk.* |
跨專案 |
| 專案內風險評估 | 專案層 proj.risk.manage |
綁專案 |
| 雲端硬碟同步設定 | 系統層 | 整合設定;專案的「初始化資料夾」走 proj.project.update |
| 標準答案匯入(不綁專案) | 系統層 evidence.use+模組內細顆 |
FR-155 R8 已裁 |
| 問卷範本庫 | 系統層 | 共用;專案內的問卷設計走 proj.survey.design |
%%{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
A[按「AI 自動分類」] --> B{系統層<br/>evidence.use?}
B -- 沒有 --> X1[選單就看不到這個模組]
B -- 有 --> C{專案層<br/>這個專案的角色有<br/>proj.evidence.classify?}
C -- 沒有 --> X2[按鈕不顯示;API 403]
C -- 有 --> D[執行]
%%{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 TB
subgraph tpl[流程範本(設計器)]
S1[規劃 stage=planning] --> S2[稽核計畫填寫 stage=ap_authoring] --> S3[稽核 stage=audit] --> S4[缺失改善 stage=poam]
end
subgraph role[專案角色頁]
R1[稽核員:勾 ap_authoring、audit]
R2[負責人:勾全部+推進任何階段]
end
subgraph run[專案執行]
P[走到稽核站] --> Q{我的角色勾了 audit?<br/>或有推進任何階段?}
Q -- 是 --> OK[能填結果、能推進]
Q -- 否 --> NO[只能看]
end
tpl -. 範本只存站代碼,不存角色 .-> run
role -. 角色勾了哪些站 .-> run
S3 -. 設計器反查:負責此站=稽核員、負責人 .-> R1
⚠️ 三個最可能出事的點
grc.job.read),換算規則要定清楚:任一細顆 → 模組開關;只有 read → 模組開關+grc.readonly。排練用真實舊庫,逐角色比對升級前後「選單與按鈕」而不是權限名。license_module 上。縮併後 evidence.use 這類開關要接住原本的 license_module,否則客戶授權會被判「沒買」。C.1 要先實查 common/authz/license.py 的對照。明確不做:拒絕規則;「推進」與「做事」分開(D3 裁後才做);專案角色匯出 JSON;部門範圍。