FR-160 · Project Role by Stage & Feature — 需求討論稿 · 2026-10-22 · 待決策者裁 D1–D8

專案角色改成「流程站+專案內功能」

系統權限縮成模組開關;專案角色照流程圖勾站、照畫面勾功能

FR-155 做完後,專案角色頁列的 13 顆權限是從程式檢查點倒推出來的,管理員看不出「專案稽核人員要勾哪幾顆」;AI 自動分類、問卷、系統安全計畫這些塞進專案頁的功能又只住在系統權限,專案角色管不到;同一個動作要在系統頁和專案頁各勾一次。本案定一條分層判準——動作有沒有「專案」這個對象——系統角色頁縮成「每模組一顆可使用+沒有專案對象的動作」;專案角色頁改成三區:流程站職責(照流程圖一站一勾)、專案內功能(含 AI 分類、問卷、SSP)、專案管理;流程設計器的「主要角色」改成從角色表反查,不再手選。

已拍板:分層判準=動作有沒有專案對象;系統層縮成模組開關(決策者 2026-10-22 選 B) D1–D8 待裁 雛形:prototype/index.html(三頁可點) 改到客戶看得到的系統角色設定,升級要換算
§1

需求背景與目標

決策者看到的問題(2026-10-22 原話)

我在專案權限那邊,要讓 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 筆有指派)但結案時沒去看它。角色真正在管的只有「能不能推進這一站」與「稽核站誰能填結果」。

分層判準(決策者 2026-10-22 拍板)

看這個動作有沒有「專案」這個對象。 問得出「哪個專案」→ 專案層;問不出 → 系統層。

程式面可機械判定:後端檢查點有先 resolve「這筆資料屬於哪個專案」的就是專案層,沒有的就是系統層。可寫守衛測試驗證,不靠人判斷。

§2

分工概述(30 秒版)

一句話:先用判準把 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 照順序。

§3

已定案事項

✅ 決策者 2026-10-22 已拍板

  • 分層判準:動作有沒有「專案」這個對象。
  • 系統層縮成一層(選項 B):每模組一顆「可使用」+沒有專案對象的動作;專案內細節全交專案角色。接受代價:系統角色頁細顆消失、升級要自動換算、版本說明要寫。
  • 專案角色頁要能回答「專案稽核人員要給他哪些」:照流程圖勾站,專案內功能點(含 AI 自動分類)納進來。
  • 流程那邊的設定要跟角色結合,不再各設各的。
§4

待決策 D1–D8

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 專案層「流程站」怎麼表示

選項:

  • (a) 每站一顆 proj.stage.<code>:proj.stage.planning、proj.stage.ap_authoring、proj.stage.audit、proj.stage.review、proj.stage.poam、proj.stage.closing,勾了=做這站的事+推進這站。站的動作(填結果、建改善計畫)後端改查對應站的顆。
  • (b) 維持現在 4 顆動作型權限,畫面上換個名字。

建議 (a):站就是工作單位,權限名對到站,流程設計器才能反查。stage_objects 表已是資料驅動,新加站就新加一顆。

D3 「推進這一站」與「做這站的事」要不要分開

例:有客戶要「稽核員填結果,但只有稽核主管能按推進」。

  • (a) 不分開:勾了站就兩者都有,清單短。
  • (b) 分開:每站兩顆,清單加倍。

建議 (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) 三處統一:里程碑結案補「被指派人也可以」;決策者說的「POA&M 負責人或專案負責人」就是這條。
  • (b) 只補里程碑。

建議 (a),寫成一條通則進 common/authz/__init__.py 決策表。

D6 流程設計器的「主要角色」欄

  • (a) 改成唯讀反查:顯示「負責此站的角色:稽核員、資深稽核員」,從角色表反查哪些專案角色勾了這站;站的主責存 proj.stage.<code>,main_role 欄不再讓人選。
  • (b) 維持可選但只列六站。

建議 (a):決策者原話「流程那邊的設定要跟角色結合」。範本上不存角色、只存站,角色改了流程不用改。

D7 專案角色頁右側「能做什麼」預覽

勾完即時顯示:能推哪幾站(照流程圖順序)、進專案會看到哪些按鈕、會收哪些通知。

  • (a) 做,與系統角色頁「可見選單預覽」同機制。
  • (b) 不做。

建議 (a),這是「看不出勾了能幹嘛」的直接解法。

D8 範例專案角色重新定義

範例角色 流程站 專案內功能 管理
負責人(預設) 全部 全部 全部
稽核員 稽核計畫填寫、稽核 佐證上傳、AI 分類、評估計畫匯入、報告檢視 —
審核者 審閱 — —
瀏覽者 — 報告檢視 —

建議照上表;「專案稽核人員」就是稽核員,管理員一眼看得出勾了兩站。

§5

做出來長什麼樣

三頁雛形在 prototype/index.html。

頁 新增/改變
1 專案角色詳情 三區:流程職責(照流程圖列六站,一站一勾,站名旁寫「勾了能做什麼」)、專案內功能(任務/佐證/問卷/SSP/評估計畫/報告/風險/檢測)、專案管理;右側「這個角色能做什麼」預覽
2 系統角色詳情(縮併後) 「權限」區改成兩段:模組開關(8 顆)、公司層動作(照模組分組);專案內細顆消失
3 流程設計器 任務節點「主要角色」改唯讀:「負責此站的角色:稽核員、資深稽核員」,旁邊連去角色頁
§6

分層表(草案,C.1 定稿)

邊界案例

功能 歸屬 理由
資源庫更新(專案頁有 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[執行]
圖 1 — 一次「按下 AI 自動分類」的判定(縮併後)
%%{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
圖 2 — 流程站與角色的結合(縮併後)
§7

風險與不做

⚠️ 三個最可能出事的點

  • 升級換算:客戶自建的系統角色勾了細顆(例:只勾 grc.job.read),換算規則要定清楚:任一細顆 → 模組開關;只有 read → 模組開關+grc.readonly。排練用真實舊庫,逐角色比對升級前後「選單與按鈕」而不是權限名。
  • 授權照(license):授權照綁在系統層能力點的 license_module 上。縮併後 evidence.use 這類開關要接住原本的 license_module,否則客戶授權會被判「沒買」。C.1 要先實查 common/authz/license.py 的對照。
  • 五套件守門補齊:AI 分類、問卷、SSP、檢測、報告各在不同套件,補專案層守門要走 path dependency 一次發版;漏一處就是「系統層放寬了、專案層又沒擋」的洞。守衛測試要掃「專案內端點必有專案層守門」。

明確不做:拒絕規則;「推進」與「做事」分開(D3 裁後才做);專案角色匯出 JSON;部門範圍。