FR-094 · 設計決策 · 2026-09-14
決定「誰能看到什麼、誰能改什麼」的三條原則,以及這三條對 13 張表+4 支 view 開隔離的影響。這份回答「為什麼這樣定」;現況一律看站首頁的總進度表與 docs/system-design/database/RLS_DESIGN.md。
🔴 這份是設計決策,不是現況。
內文的數字與待辦停在 2026-09-14 定稿當時,之後實作改動的結果不回頭改寫這裡。現況看 README.md 總進度表與 RLS_DESIGN.md。
租戶是資料歸屬的邊界,一筆資料只屬一個租戶,不跨租戶指派、不跨租戶操作。階層只給往下的唯讀監看,要在某租戶內操作就成為該租戶成員、用切換進去做。部門只記「誰負責改」,不擋讀取,可見度靠角色與參與關係。
| 原則 | 白話 | 資料庫怎麼落 | 程式怎麼落 |
|---|---|---|---|
| ① 租戶不跨 | 一筆資料只屬於一個租戶。別租戶的人要看,只能靠「原廠公版」「母租戶標記分享給子樹」或「複製一份過去」,不能把人指派進來 | 每張表的查詢規則只認 super admin 或「租戶路徑前綴」;公版用 scope='SYSTEM'(既有三張用 is_builtin 不回改) |
指派人、參與者、審核者的候選名單只列本租戶(含切進來的)帳號 |
| ② 階層只往下看 | 母租戶看得到子租戶的專案、任務、缺失,但不在子租戶裡操作。要操作就由子租戶管理員把人加進來、給角色,此人切到子租戶做事,紀錄留在子租戶 | 前綴比對天生就是「上看下、下看不到上、兄弟互不見」,不加「下看上」的分支 | 一個帳號可隸屬多個租戶(user_tenants)、切租戶功能已有;不另做跨租戶指派 |
| ③ 部門不是牆 | 部門是租戶內的歸屬標籤與寫入範圍。誰能看靠角色與參與關係(我被指派、我是專案參與者),跨部門協作是常態 | 查詢規則一律不加部門條件;改、刪規則不綁部門(要收緊走「歸屬部門或管理角色」分支,另案) | 清單頁可用部門當篩選器,不當過濾牆 |
多租戶階層的主流做法一致:階層只給監看,不給操作;要操作就成為那個租戶的成員。
| 平台 | 上層對下層 | 要在下層操作 |
|---|---|---|
| AWS Organizations | 管理帳號看成員帳號的帳單、合規、稽核紀錄 | 切換角色進成員帳號,紀錄留在成員帳號 |
| Google Cloud 資源階層 | 組織層看全部專案 | 權限往下繼承,不往上索取 |
| Microsoft Dataverse 業務單位 | 上層可讀下層 | 寫入綁資料所屬單位,靠角色取得 |
| Azure Lighthouse | 代管方看客戶訂閱 | 客戶明確授權角色,代管方切到客戶脈絡操作,可隨時收回 |
| Okta/Auth0 多組織 | 母組織管子組織設定 | 使用者是子組織成員,一個帳號可屬多組織 |
部門可見度則是三檔制,預設共享、例外收緊、收緊靠角色與參與關係:
| 檔位 | 意思 | 例子 |
|---|---|---|
| 共享可讀、歸屬部門可改 | 公司資產誰都查得到,負責單位改 | ServiceNow CMDB、Jira 專案 |
| 共享可讀、改靠角色 | 部門只是分類 | Salesforce 預設公開讀寫再用角色收 |
| 私有、參與者可見 | 敏感資料逐筆收緊 | Salesforce 私有物件+分享規則、GRC 產品的稽核證據 |
| 資料 | 讀 | 改/刪 | 理由 |
|---|---|---|---|
| 設備、資訊系統 | 全租戶 | 歸屬部門或管理角色 | 公司資產清單,稽核要跨部門查 |
| 合規框架、模組框架、檢測方案、流程範本 | 全租戶(含公版) | 歸屬部門或管理角色 | 參考資料,本來就是給大家用 |
| 問卷 | 全租戶(本租戶自建) | 歸屬部門或管理角色 | 沒有公版、不需要公版:租戶各自建,任務引用時複製進任務。出貨基線零筆問卷;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 預設部門、管理員角色、儲存設定。
| 卡 | 表 | 租戶原則下要不要改規則 | 部門原則下要不要改規則 | 結論 |
|---|---|---|---|---|
| .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 |
| 案 | 做哪幾張 | 修到什麼 | 沒修到什麼 |
|---|---|---|---|
| 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 是唯一的牆。
| 選項 | 為什麼不採 |
|---|---|
| 支援「母租戶把任務指派給子租戶帳號」,規則加「參與者可見」讓下看上 | 被指派人要看的東西散在十幾張表(專案、流程、問卷、人名),逐張開洞等於把牆拆掉;操作紀錄會留在別人租戶,責任歸屬不清。業界沒有這種做法,改用「多隸屬+切租戶」 |
| 部門當第二道前綴牆(部門樹也「上看下」) | DEV 任務指派 68% 跨部門,設備、資訊系統、問卷都是跨部門在用;擋了處處卡。業界部門只當篩選與寫入歸屬 |
修改共用 helper app_tenant_allowed_for_session 加「下看上」 |
12 張以上的表共用,改它等於全部子租戶看到母租戶全部資料 |
用 can_read_all_orgs 逃生口補改、刪規則 |
逃生口是程式層在四處手動開的旗標,開在誰身上沒有規範;規則本身不該綁部門,拿掉條件比補逃生口正確 |
| 出現這件事 | 該改什麼 |
|---|---|
| 客戶明確要求「總部的人不加入子公司也能在子公司專案裡操作」 | 重新評估原則②,但仍應以「代管授權」形式(子公司明確授權、可收回、紀錄留子公司)落地,不是開洞 |
| 客戶要求「部門之間互相看不到」 | 用「參與者可見」分支解,不把部門變成前綴牆 |
| 出貨後發現某類資料需要逐筆機密 | 加逐筆旗標(機密=只有參與者可見),不動部門與租戶規則 |