01 / WORK / CASE STUDY
多租戶 SaaS 人資系統
涵蓋出勤、排班、薪資、簽核到招募的多租戶人資平台,36 個功能模組;目前處於驗收與修復階段。
- TYPE
- FULL STACK
- SCOPE
- 公司內部 · 驗收修復階段
- STACK
- DJANGO · DRF · MYSQL · REDIS · CELERY · REACT
- LINKS
- 公司內部專案(不公開)
01 / PROBLEM
中小企業的 HR 事務常散落在 Excel、紙本簽核與各自為政的工具之間,難以稽核也容易出錯,且每家公司都要重複導入一次。這個系統以多租戶 SaaS 的形態切入:單一部署服務多個組織,各租戶資料嚴格隔離、依訂閱開關功能模組,並內建台灣勞基法的合規檢查。
02 / CONSTRAINTS
- 公司內部專案,程式碼不公開;目前以合成種子資料進行驗收,尚未正式上線。
- 多租戶隔離是硬性要求:任何一條查詢漏掉租戶條件都是資料外洩。
- 需符合台灣勞基法(工時上限、加班倍率、扣繳)並支援繁中/簡中/英文三語。
03 / ARCHITECTURE
模組化單體:Django 4.2 + DRF 依領域切成 36 個功能 app(出勤、排班、薪資、簽核、招募、資產、勞健保⋯),約 215 個資料模型、188 個資源路由,展開後在驗收中實測了 728 個端點。刻意不拆微服務——薪資與簽核這類跨模組流程在單一交易邊界裡簡單得多。
多租戶採 shared-schema、row-level 隔離:middleware 解析租戶,304 個類別繼承租戶感知基底。非同步層以 Celery + Beat 處理班表產生、出勤歸檔與法規/假日同步;Redis 作快取與 Channel;資料庫可依環境切換 PostgreSQL 或 MySQL;CI 用 GitHub Actions + pre-commit,並附 Prometheus / Grafana / Loki 可觀測性編排。
04 / RESPONSIBILITIES
前後端獨立開發(後端 434、前端 123 個 commit 皆出自我的兩組 git 身分):資料模型與多租戶機制、權限體系、各領域模組、Celery 背景任務、React 前端與 CI。
05 / CHALLENGES → SOLUTIONS
CHALLENGE
資安稽核發現:部分自訂 API action 繞過了租戶過濾,可跨租戶操作帳號。
SOLUTION
把隔離下沉到基底(TenantAwareModel + middleware 統一解析),逐一修補繞過 queryset 的 action。該輪稽核共 35 項發現(含 2 項 Critical)全數確認,30 項修復完成、5 項部分修復,尚待 staging 環境複驗——這個狀態如實記錄。
CHALLENGE
薪資 API 的快取鍵沒有包含使用者身分——同一個 TTL 窗內,一般員工可能命中管理員的快取,看到全公司薪資。
SOLUTION
在快取裝飾器加入 vary_by_user,把使用者折進快取鍵;並用真實 HTTP 呼叫寫了回歸測試,證明兩個使用者互相看不到彼此的快取。
CHALLENGE
台灣的國定假日與法規參數每年變動,不能靠人工同步。
SOLUTION
Celery Beat 排程化:每年同步隔年假日、每日檢查法規到期、每週預告即將到來的假日;任務帶自動重試與指數退避。
06 / SYSTEM FACTS
36
功能模組
215
資料模型
728
端點實測
87.5%
驗收通過率
07 / LESSONS
快取設計就是權限設計——薪資快取洩漏的根因,是快取鍵少了身分維度。在多租戶系統裡,這種錯誤不是效能問題,是資料外洩。
系統性的漏洞往往來自模型設計:全域角色與租戶角色雙軌並存,連帶引發提權與跨租戶問題。重來一次,我會從第一天就統一以租戶維度設計權限。
NEXT
AI 美甲平台