跳至主要內容

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 美甲平台