Day 17:多租戶隔離,讓每個經銷據點只看到自己的資料 結尾留下一句話,角色矩陣跟多租戶隔離這兩層機制現在都各自存在了,但兩者疊加在一起運作時是否真的正確,這件事還沒有真正驗證過。
今天要處理的正是這句話,也是第五階段「多角色權限與多租戶」的最後一天。
回頭看這兩天各自的驗證方式,會發現一件容易被忽略的事。Day 16 驗證角色矩陣時,用的三組帳號分別是倉管、業務、財務,但這三組帳號並沒有特別區分所屬據點,驗證的重點純粹是「這個角色能不能操作這個功能」。Day 17 驗證多租戶隔離時,用的兩組帳號分別屬於台北據點跟高雄據點,角色卻統一設成業務,驗證的重點純粹是「這個據點能不能看到別的據點的資料」。
兩天的驗證都只單獨測了一個維度。角色矩陣的驗證裡,據點是被刻意固定住的變因;多租戶隔離的驗證裡,角色又反過來變成被固定住的變因。從來沒有一次,用一個同時具備角色跟據點兩種真實身分的帳號,例如高雄據點的倉管,或是台北據點的財務,實際登入操作過。
這種各自為政的驗證方式,藏著一個容易被忽略的風險。兩層限制各自運作正確,不代表兩層疊加在一起也一定正確。如果其中一層的判斷邏輯寫錯了順序,比如多租戶隔離的查詢條件不小心寫在角色矩陣判斷之前的某個環節,可能會把原本該被角色矩陣允許的操作,錯誤地連帶擋下;反過來,角色矩陣裡如果有一處邏輯遺漏,也可能讓多租戶隔離原本該限制住的資料,意外從某個沒被覆蓋到的角落露出來。這類問題的共同點,是單獨測任何一層都測不出來,只有把兩層疊在同一個帳號、同一次操作上,才會浮現。
今天的任務範圍先講清楚,不新增任何新機制,商品、訂單、客戶、訂單明細的欄位定義完全沿用前面兩天已經定案的內容。要做的事情,是挑選幾組具體的角色加據點組合,實際登入操作一次,驗證兩層機制疊加時的結果是否符合預期,驗證完成後,回頭具體回顧這個階段三天的進度。
驗證的做法很單純,準備幾組同時具備角色跟據點兩種身分的帳號,逐一登入,對照 Day 16 那張角色權限矩陣跟 Day 17 建立的據點隔離,檢查兩層限制是不是同時成立、彼此不衝突。
第一組,高雄據點的倉管。準備一組帳號,role 設成 warehouse,branch_id 指向高雄據點。登入後打開訂單列表,畫面上只有高雄據點的訂單,台北據點的訂單完全看不到,這是 BranchScope 在發揮作用。點開其中一張高雄訂單的訂單明細,新增跟刪除按鈕都正常顯示,符合矩陣裡倉管在訂單明細這兩欄的權限,這是 OrderItemPolicy 在發揮作用。切到商品列表,編輯按鈕也正常顯示,同樣符合矩陣。這組驗證確認了一件事,角色矩陣賦予倉管的操作權限,跟多租戶隔離限制的資料範圍,兩者同時成立,倉管看得到的、能操作的,都精準落在高雄據點這個範圍之內,沒有互相干擾。
第二組,台北據點的財務。準備另一組帳號,role 設成 finance,branch_id 指向台北據點。登入後打開訂單列表,只看得到台北據點的訂單,高雄的訂單一筆都不會出現。依矩陣,財務角色只能檢視訂單,不能新增或編輯,畫面上果然找不到任何建立或編輯的入口,訂單明細的新增按鈕也沒有出現。這組驗證確認了另一件更容易被忽略的事,即使角色權限相對受限,資料範圍的隔離依然正確套用,不會因為這個角色能做的事情本來就不多,就連帶把據點隔離也一起鬆綁。財務帳號看得到的訂單雖然數量有限,但範圍依然準確地只落在台北。
兩組驗證合起來看,可以確認角色矩陣與多租戶隔離是真正獨立疊加的兩層限制,不會因為其中一層寬鬆或嚴格,影響另一層的判斷結果。倉管在高雄能做的事情比財務在台北多得多,但兩人各自看到的資料範圍,都精準卡在自己所屬的據點,沒有越界。

驗證這類疊加情境時,真正該留意的是兩層限制的判斷順序有沒有被寫成互相依賴的關係。回頭看 Day 17 建立 BranchScope 的方式,這個 Global Scope 只負責在查詢語句上加一句 where('branch_id', ...),跟 Day 16 寫進各個 Policy 類別裡的角色判斷,是完全獨立的兩段程式碼,一段管操作能不能做,一段管查詢範圍多大,中間沒有互相呼叫,也沒有誰依賴誰的執行結果。如果驗證過程中真的發現兩層機制打架,比如某個角色明明該有的操作按鈕不見了,或是某個據點的資料意外跑出來,最先該檢查的方向,就是確認這兩段邏輯是不是被誤寫成互相依賴或彼此覆蓋,而不是各自獨立運作、同時疊加。這正是 Day 17 定案時強調過的設計原則,也是今天疊加驗證能夠一次就通過的原因。
今天的驗證流程走完,但這裡要誠實點出一個目前完全沒觸及的範圍。今天示範的高雄倉管、台北財務,只是三個角色乘上兩個經銷據點裡的兩組樣本,實際的組合數遠比今天示範的更多,倉管在台北是什麼樣子、業務在高雄又是什麼樣子,今天都沒有逐一走過。今天驗證的是具代表性的樣本,用來確認疊加運作的邏輯正確,不是窮舉了所有組合的完整測試。
這個落差不是這個階段的任務範圍,而是規模持續成長之後理應建立的常態性檢查機制。
未來如果角色或據點的數量繼續增加,比如新開一個台中據點,或是多出一個客服角色,該怎麼有系統地確認每一組新組合都正確運作,而不是每次都得靠人工一組一組手動登入檢查,這是留給後續階段視需要處理的問題,這裡不展開任何具體實作方向。老實承認這個落差,比假裝今天已經驗證過所有可能的組合更有意義。
今天是第五階段「多角色權限與多租戶」的收尾篇,適合停下來完整回顧這三天走過的路徑。
Day 16:設計一份貼近真實團隊的角色權限矩陣 把倉管、業務、財務三個角色的職責差異,畫成一張角色對應模組操作的具體矩陣,實作進 Day 15 已經接上的 Policy 機制裡,讓同一套後台依登入者身分,呈現出真正不同的操作介面,倉管看到的是庫存管理視角,業務看到的是接單視角,財務看到的是覆核視角。Day 17:多租戶隔離,讓每個經銷據點只看到自己的資料 接著定案多租戶隔離,讓後台依登入使用者所屬的經銷據點,自動限制客戶、訂單、訂單明細這幾個模組的查詢範圍,不同據點的人看到的資料,第一次真正不一樣。今天則把這兩層機制疊加起來,用高雄倉管、台北財務這兩組具體帳號實際操作,確認兩者各自運作正確,同時疊加也不互相打架。
把這階段前後對照一下,落差相當具體。這個階段開始之前,這套後台裡任何登入的使用者,都能無差別操作任何資料,也看得到全部據點的資料,一個帳號跟另一個帳號之間,除了登入資訊不同,畫面跟資料範圍完全一樣。階段結束的今天,一個帳號打開後台,看到的操作按鈕跟看到的資料範圍,都精準對應這個人真實的身分與所屬據點。這是全系列第一次,讓後台具備真正貼近實際商業結構的樣貌,而不只是一套功能齊全的展示品。
這條路徑也呼應系列一直在講的那條主線,陽春後台逐步加深。前面幾個階段做的事情,是把資料本身、資料之間的關聯、資料的嚴謹度做好,商品、訂單、客戶怎麼定義欄位,彼此怎麼關聯,填進去的值合不合理,這些進展發生在資料這個維度上。這個階段做的事情性質不同,補上的是後台的身分跟邊界,誰能看到什麼、誰能做什麼,這件事到今天才第一次被真正落實。兩種進展性質不同,但同樣是一套可上線系統不可或缺的地基,少了任何一種,都稱不上是一套能交給真實團隊使用的後台。
角色權限矩陣與多租戶隔離這兩層機制,今天實際疊加驗證過了。高雄據點的倉管能操作訂單明細,也只看得到高雄的資料;台北據點的財務只能檢視訂單,也只看得到台北的資料。兩層限制同時成立,互不打架。這套後台第一次具備了真正貼近實際商業結構的身分與邊界,不同的人打開同一套系統,看到的按鈕跟資料都精準對應各自的位置。
但管理者如果想知道現在有多少筆待處理的訂單、庫存還剩多少,仍然得逐一點開商品、訂單這幾個 Resource,才能一點一點拼湊出目前的現況,後台目前沒有一個地方,能讓人一打開就看懂整體現況。
第一個 Widget,把訂單數字擺上首頁,是接下來要處理的內容。