FR-094 · 設計決策 · 2026-09-14

租戶是牆、階層只能往下看、部門不是牆

決定「誰能看到什麼、誰能改什麼」的三條原則,以及這三條對 13 張表+4 支 view 開隔離的影響。這份回答「為什麼這樣定」;現況一律看站首頁的總進度表與 docs/system-design/database/RLS_DESIGN.md。

三原則已定 B 案定案 部門條件要先修

🔴 這份是設計決策,不是現況。

內文的數字與待辦停在 2026-09-14 定稿當時,之後實作改動的結果不回頭改寫這裡。現況看 README.md 總進度表與 RLS_DESIGN.md。

§1

一句話

租戶是資料歸屬的邊界,一筆資料只屬一個租戶,不跨租戶指派、不跨租戶操作。階層只給往下的唯讀監看,要在某租戶內操作就成為該租戶成員、用切換進去做。部門只記「誰負責改」,不擋讀取,可見度靠角色與參與關係。

§2

三條可見度原則

原則 白話 資料庫怎麼落 程式怎麼落
① 租戶不跨 一筆資料只屬於一個租戶。別租戶的人要看,只能靠「原廠公版」「母租戶標記分享給子樹」或「複製一份過去」,不能把人指派進來 每張表的查詢規則只認 super admin 或「租戶路徑前綴」;公版用 scope='SYSTEM'(既有三張用 is_builtin 不回改) 指派人、參與者、審核者的候選名單只列本租戶(含切進來的)帳號
② 階層只往下看 母租戶看得到子租戶的專案、任務、缺失,但不在子租戶裡操作。要操作就由子租戶管理員把人加進來、給角色,此人切到子租戶做事,紀錄留在子租戶 前綴比對天生就是「上看下、下看不到上、兄弟互不見」,不加「下看上」的分支 一個帳號可隸屬多個租戶(user_tenants)、切租戶功能已有;不另做跨租戶指派
③ 部門不是牆 部門是租戶內的歸屬標籤與寫入範圍。誰能看靠角色與參與關係(我被指派、我是專案參與者),跨部門協作是常態 查詢規則一律不加部門條件;改、刪規則不綁部門(要收緊走「歸屬部門或管理角色」分支,另案) 清單頁可用部門當篩選器,不當過濾牆
§3

業界怎麼定義

多租戶階層的主流做法一致:階層只給監看,不給操作;要操作就成為那個租戶的成員。

平台 上層對下層 要在下層操作
AWS Organizations 管理帳號看成員帳號的帳單、合規、稽核紀錄 切換角色進成員帳號,紀錄留在成員帳號
Google Cloud 資源階層 組織層看全部專案 權限往下繼承,不往上索取
Microsoft Dataverse 業務單位 上層可讀下層 寫入綁資料所屬單位,靠角色取得
Azure Lighthouse 代管方看客戶訂閱 客戶明確授權角色,代管方切到客戶脈絡操作,可隨時收回
Okta/Auth0 多組織 母組織管子組織設定 使用者是子組織成員,一個帳號可屬多組織

部門可見度則是三檔制,預設共享、例外收緊、收緊靠角色與參與關係:

檔位 意思 例子
共享可讀、歸屬部門可改 公司資產誰都查得到,負責單位改 ServiceNow CMDB、Jira 專案
共享可讀、改靠角色 部門只是分類 Salesforce 預設公開讀寫再用角色收
私有、參與者可見 敏感資料逐筆收緊 Salesforce 私有物件+分享規則、GRC 產品的稽核證據
§4

每類資料的檔位

資料 讀 改/刪 理由
設備、資訊系統 全租戶 歸屬部門或管理角色 公司資產清單,稽核要跨部門查
合規框架、模組框架、檢測方案、流程範本 全租戶(含公版) 歸屬部門或管理角色 參考資料,本來就是給大家用
問卷 全租戶(本租戶自建) 歸屬部門或管理角色 沒有公版、不需要公版:租戶各自建,任務引用時複製進任務。出貨基線零筆問卷;DEV 掛 tenant 1 的 8 份是 2025 年手建測試資料,不是公版
專案、任務、流程執行 全租戶,程式層依角色收成「我參與的」 專案參與者、被指派人、管理角色 寫入綁參與關係最自然
問卷作答、證據檔、缺失改善計畫 全租戶;日後可逐筆標「機密」收成參與者 被指派人、專案參與者 真正可能要「特定不能瀏覽」的是這類,用逐筆旗標不用部門
使用者、角色、部門名冊 全租戶 管理角色 選人、指派都要查
SSP、稽核報告 全租戶 專案參與者 沒有部門欄位,也不需要加
原廠公版 所有租戶 平台管理員 出貨基線的公版只有三類(scripts/init/04、05 實查):合規框架 CMMC 2.0 L1/L2(oscal.*,全域共用無租戶欄位)、流程範本 2 支(flow_templates.is_builtin)、掃描設定檔 10 套 TWGCB(detection_profiles.scope='SYSTEM')。模組框架、工作流程範本有公版機制但出貨零筆(workflow_templates 基線刻意清空、04 有非空即報錯的守衛);DEV 上掛 tenant 1 的 59 支 workflow_templates、8 份問卷、1 筆模組框架都是測試資料,不是公版

公版的「共用」是隔離規則多開一條「標了公版就放行讀」的門,寫入仍只有平台管理員;子租戶要改就複製一份成自己的再改。新租戶建立時不複製參考資料,只 seed 預設部門、管理員角色、儲存設定。

§5

對 FR-094 八張卡的影響

卡 表 租戶原則下要不要改規則 部門原則下要不要改規則 結論
.1a CM-1767 排程系統身分 不用 不用 照派
CM-1559 fail-open 收緊 不用 不用 第二刀(tenant_id 空值不再算 super admin)DEV 可驗;第一刀(無身分直接拒絕)等有可信驗證環境
.2a CM-1768 projects、雲端硬碟串接 不用(不支援跨租戶指派,前綴規則即正解) 不用 照派
.2b CM-1769 user_roles/user_tenants/user_org_units 不用(卡片已設計本人恆可見) 不用 照派
.2c CM-1770 poams、證據分類、job_executions、framework_parse_jobs 不用 不用 .1a+1559 後派
.2d CM-1771 workflow_executions、4 支 view 不用 要:既有改、刪規則綁部門且無逃生口,開了跨部門推進任務會更新 0 筆不報錯 開之前把改、刪規則的部門條件換成租戶條件
.2e CM-1772 workflow_templates 不用 要:同上 同上
.3a CM-1773 問卷 12 張裸表 規則錨在任務或問卷主表,不經專案反查 不用 方案定案後派

另外兩件不在八張卡內、由本設計長出來的:

事 為什麼 去向
指派人、參與者候選名單擋掉非本租戶帳號;SPEC 寫明「不支援跨租戶指派」 原則①的程式面。不擋,客戶做了會遇到資料靜默消失 另開小卡,不擋 1.20.0
母租戶自訂的模組框架、檢測方案、流程範本、範本庫分享給子樹(scope 加一檔) 原則①的「明確分享」通道。三張既有表現在就擋住母租戶自訂資源,只是沒人踩到 另開卡,不擋 1.20.0
§6

這版做哪幾張:B 案

案 做哪幾張 修到什麼 沒修到什麼
A .1a+CM-1559 全部 「沒身分就當超級管理員」關掉 決策者親測的兩個症狀都還在;1559 第一刀回歸面最大、Drive 路徑 DEV 驗不出、要關的洞落地版目前打不到
B(採用) .1a+.2a+.2d+1559 第二刀 親測的兩個症狀修掉;1559 風險小的那半收進 1.1.0 11 張表落地版要靠直連資料庫或漏驗歸屬的 API 才打得到,排 1.20.0 之後
C 八張全做 全部隔離 五棒重產 schema 與 FR-093 出貨鏈撞、兩支 jedi 套件擠同一次發版、問卷方案要先實查

採 B 的判斷:現況一般帳號的可見範圍靠每支查詢各自寫條件撐著,不是牆;三條路現在就打得到(管理員切子租戶、不驗歸屬的任務詳細 API、未來漏寫條件的新 API)。落地版一台機一個客戶,剩下 11 張表洩漏的是同公司內部子租戶的資料,不擋出貨;SaaS 上線前 C 必須做完,那時 RLS 是唯一的牆。

§7

被排除的選項

選項 為什麼不採
支援「母租戶把任務指派給子租戶帳號」,規則加「參與者可見」讓下看上 被指派人要看的東西散在十幾張表(專案、流程、問卷、人名),逐張開洞等於把牆拆掉;操作紀錄會留在別人租戶,責任歸屬不清。業界沒有這種做法,改用「多隸屬+切租戶」
部門當第二道前綴牆(部門樹也「上看下」) DEV 任務指派 68% 跨部門,設備、資訊系統、問卷都是跨部門在用;擋了處處卡。業界部門只當篩選與寫入歸屬
修改共用 helper app_tenant_allowed_for_session 加「下看上」 12 張以上的表共用,改它等於全部子租戶看到母租戶全部資料
用 can_read_all_orgs 逃生口補改、刪規則 逃生口是程式層在四處手動開的旗標,開在誰身上沒有規範;規則本身不該綁部門,拿掉條件比補逃生口正確
§8

反悔條件

出現這件事 該改什麼
客戶明確要求「總部的人不加入子公司也能在子公司專案裡操作」 重新評估原則②,但仍應以「代管授權」形式(子公司明確授權、可收回、紀錄留子公司)落地,不是開洞
客戶要求「部門之間互相看不到」 用「參與者可見」分支解,不把部門變成前綴牆
出貨後發現某類資料需要逐筆機密 加逐筆旗標(機密=只有參與者可見),不動部門與租戶規則