Files
hr-portal/ARCHITECTURE.md
Porsche Chen 360533393f feat: HR Portal - Complete Multi-Tenant System with Redis Session Storage
Major Features:
-  Multi-tenant architecture (tenant isolation)
-  Employee CRUD with lifecycle management (onboarding/offboarding)
-  Department tree structure with email domain management
-  Company info management (single-record editing)
-  System functions CRUD (permission management)
-  Email account management (multi-account per employee)
-  Keycloak SSO integration (auth.lab.taipei)
-  Redis session storage (10.1.0.254:6379)
  - Solves Cookie 4KB limitation
  - Cross-system session sharing
  - Sliding expiration (8 hours)
  - Automatic token refresh

Technical Stack:
Backend:
- FastAPI + SQLAlchemy
- PostgreSQL 16 (10.1.0.20:5433)
- Keycloak Admin API integration
- Docker Mailserver integration (SSH)
- Alembic migrations

Frontend:
- Next.js 14 (App Router)
- NextAuth 4 with Keycloak Provider
- Redis session storage (ioredis)
- Tailwind CSS

Infrastructure:
- Redis 7 (10.1.0.254:6379) - Session + Cache
- Keycloak 26.1.0 (auth.lab.taipei)
- Docker Mailserver (10.1.0.254)

Architecture Highlights:
- Session管理由 Keycloak + Redis 統一控制
- 支援多系統 (HR/WebMail/Calendar/Drive/Office) 共享 session
- Token 自動刷新,異質服務整合
- 未來可無縫遷移到雲端

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-23 20:12:43 +08:00

512 lines
12 KiB
Markdown

# 🏢 人資管理系統架構設計
## 📋 系統概述
**HR Portal** - 整合 Keycloak SSO 的企業人資管理平台
### 核心功能
1.**SSO 統一登入** - Keycloak OAuth2/OIDC
2. 👤 **員工基本資料管理**
3. 📧 **電子郵件帳號管理** - Docker Mailserver 整合
4. 💾 **網路硬碟配額管理** - NAS 整合
5. 🔐 **系統權限管理**
6. 📊 **個人化儀表板**
---
## 🏗️ 技術架構
### 技術堆疊
#### 前端
- **框架**: React 18 + TypeScript
- **UI 庫**: Ant Design / Material-UI
- **狀態管理**: React Query + Zustand
- **路由**: React Router v6
- **HTTP**: Axios
- **認證**: @react-keycloak/web
#### 後端
- **框架**: FastAPI (Python 3.11+)
- **資料庫**: PostgreSQL 16
- **ORM**: SQLAlchemy 2.0
- **認證**: python-keycloak
- **API 文檔**: OpenAPI/Swagger
#### 基礎設施
- **反向代理**: Traefik
- **SSO**: Keycloak
- **郵件**: Docker Mailserver
- **儲存**: Synology NAS (WebDAV/SMB)
- **容器化**: Docker + Docker Compose
---
## 🗂️ 資料庫設計
### 員工資料表 (employees)
```sql
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
keycloak_user_id UUID UNIQUE NOT NULL, -- Keycloak User ID
employee_id VARCHAR(20) UNIQUE NOT NULL, -- 員工編號
username VARCHAR(100) UNIQUE NOT NULL, -- 登入帳號
-- 基本資料
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
chinese_name VARCHAR(50),
email VARCHAR(255) UNIQUE NOT NULL,
phone VARCHAR(20),
mobile VARCHAR(20),
-- 任職資訊
department VARCHAR(100),
position VARCHAR(100),
job_title VARCHAR(100),
employment_type VARCHAR(20), -- full-time, part-time, contractor
hire_date DATE,
termination_date DATE,
-- 狀態
status VARCHAR(20) DEFAULT 'active', -- active, inactive, suspended
-- 審計欄位
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by VARCHAR(100),
updated_by VARCHAR(100)
);
-- 索引
CREATE INDEX idx_employees_keycloak_id ON employees(keycloak_user_id);
CREATE INDEX idx_employees_status ON employees(status);
CREATE INDEX idx_employees_department ON employees(department);
```
### 郵件帳號表 (email_accounts)
```sql
CREATE TABLE email_accounts (
id SERIAL PRIMARY KEY,
employee_id INTEGER REFERENCES employees(id) ON DELETE CASCADE,
email_address VARCHAR(255) UNIQUE NOT NULL,
mailbox_quota_mb INTEGER DEFAULT 1024, -- 郵箱配額 (MB)
mailbox_used_mb INTEGER DEFAULT 0,
-- 郵件設定
forward_to VARCHAR(255),
auto_reply BOOLEAN DEFAULT FALSE,
auto_reply_message TEXT,
-- 狀態
is_active BOOLEAN DEFAULT TRUE,
-- 審計
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_email_accounts_employee ON email_accounts(employee_id);
```
### 網路硬碟表 (network_drives)
```sql
CREATE TABLE network_drives (
id SERIAL PRIMARY KEY,
employee_id INTEGER REFERENCES employees(id) ON DELETE CASCADE,
-- 硬碟資訊
drive_name VARCHAR(100) NOT NULL, -- 個人硬碟名稱
drive_path VARCHAR(500) NOT NULL, -- NAS 路徑
quota_gb INTEGER DEFAULT 10, -- 配額 (GB)
used_gb DECIMAL(10,2) DEFAULT 0,
-- WebDAV 設定
webdav_url VARCHAR(500),
smb_path VARCHAR(500),
-- 權限
can_share BOOLEAN DEFAULT FALSE,
-- 狀態
is_active BOOLEAN DEFAULT TRUE,
-- 審計
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_network_drives_employee ON network_drives(employee_id);
```
### 系統權限表 (system_permissions)
```sql
CREATE TABLE system_permissions (
id SERIAL PRIMARY KEY,
employee_id INTEGER REFERENCES employees(id) ON DELETE CASCADE,
system_name VARCHAR(100) NOT NULL, -- gitea, keycloak, portainer 等
system_url VARCHAR(500),
access_level VARCHAR(50), -- admin, user, readonly
-- 狀態
is_active BOOLEAN DEFAULT TRUE,
granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
granted_by VARCHAR(100),
UNIQUE(employee_id, system_name)
);
CREATE INDEX idx_system_permissions_employee ON system_permissions(employee_id);
```
### 審計日誌表 (audit_logs)
```sql
CREATE TABLE audit_logs (
id SERIAL PRIMARY KEY,
employee_id INTEGER REFERENCES employees(id),
action VARCHAR(50) NOT NULL, -- create, update, delete, login
resource_type VARCHAR(50), -- employee, email, drive
resource_id INTEGER,
old_value JSONB,
new_value JSONB,
ip_address VARCHAR(50),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_audit_logs_employee ON audit_logs(employee_id);
CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at);
```
---
## 🔐 SSO 認證流程
### 登入流程
```
用戶訪問 https://hr.porscheworld.tw
檢查是否已登入 (檢查 Token)
未登入 → 重定向到 Keycloak
Keycloak 認證
返回 Authorization Code
後端用 Code 換取 Access Token
驗證 Token + 取得用戶資訊
查詢/創建員工記錄
返回用戶 Session
顯示個人化儀表板
```
---
## 🌐 API 端點設計
### 認證相關
```
GET /api/auth/login - 發起 SSO 登入
GET /api/auth/callback - SSO 回調處理
POST /api/auth/logout - 登出
GET /api/auth/me - 取得當前用戶資訊
GET /api/auth/refresh - 刷新 Token
```
### 員工管理
```
GET /api/employees - 列出員工 (支援分頁/搜尋)
GET /api/employees/:id - 取得員工詳情
POST /api/employees - 創建員工
PUT /api/employees/:id - 更新員工
DELETE /api/employees/:id - 刪除員工
GET /api/employees/me - 取得當前登入員工資訊
PUT /api/employees/me - 更新個人資料
```
### 郵件帳號管理
```
GET /api/emails - 列出所有郵件帳號
GET /api/emails/:id - 取得郵件帳號詳情
POST /api/emails - 創建郵件帳號
PUT /api/emails/:id - 更新郵件帳號
DELETE /api/emails/:id - 刪除郵件帳號
POST /api/emails/:id/quota - 調整郵箱配額
GET /api/emails/me - 取得我的郵件帳號
```
### 網路硬碟管理
```
GET /api/drives - 列出所有網路硬碟
GET /api/drives/:id - 取得硬碟詳情
POST /api/drives - 創建硬碟配額
PUT /api/drives/:id - 更新硬碟設定
DELETE /api/drives/:id - 刪除硬碟配額
GET /api/drives/me - 取得我的硬碟資訊
GET /api/drives/me/usage - 取得硬碟使用量
```
### 系統權限管理
```
GET /api/permissions - 列出權限
POST /api/permissions - 授予權限
DELETE /api/permissions/:id - 撤銷權限
GET /api/permissions/me - 取得我的系統權限列表
```
### 儀表板
```
GET /api/dashboard/stats - 取得統計數據
GET /api/dashboard/activity - 取得最近活動
```
### 審計日誌
```
GET /api/audit-logs - 查詢審計日誌
GET /api/audit-logs/me - 查詢我的操作記錄
```
---
## 🎨 前端頁面結構
### 公開頁面
- `/login` - 登入頁 (重定向到 Keycloak)
- `/callback` - SSO 回調頁面
### 管理端 (需要 admin 權限)
- `/admin/dashboard` - 管理儀表板
- `/admin/employees` - 員工列表
- `/admin/employees/new` - 新增員工
- `/admin/employees/:id` - 員工詳情/編輯
- `/admin/emails` - 郵件帳號管理
- `/admin/drives` - 硬碟配額管理
- `/admin/permissions` - 權限管理
- `/admin/audit-logs` - 審計日誌
### 個人端 (所有登入用戶)
- `/` - 個人儀表板
- `/profile` - 個人資料
- `/my-email` - 我的郵件設定
- `/my-drive` - 我的網路硬碟
- `/my-systems` - 我的系統權限
---
## 🔗 系統整合
### 1. Keycloak 整合
```python
# 創建員工時同步到 Keycloak
def create_employee(employee_data):
# 1. 在 Keycloak 創建用戶
kc_user = keycloak_admin.create_user({
'username': employee_data['username'],
'email': employee_data['email'],
'firstName': employee_data['first_name'],
'lastName': employee_data['last_name'],
'enabled': True
})
# 2. 在本地資料庫創建記錄
employee = Employee(
keycloak_user_id=kc_user['id'],
**employee_data
)
db.add(employee)
return employee
```
### 2. Docker Mailserver 整合
```python
# 創建郵件帳號
def create_email_account(employee_id, email, password):
# 1. 在 Docker Mailserver 創建帳號
docker_exec(
'mailserver',
f'setup email add {email} {password}'
)
# 2. 記錄到資料庫
email_account = EmailAccount(
employee_id=employee_id,
email_address=email,
mailbox_quota_mb=1024
)
db.add(email_account)
return email_account
```
### 3. NAS 儲存整合
```python
# 創建網路硬碟
def create_network_drive(employee):
username = employee.username
# 1. 在 NAS 創建個人資料夾
nas_path = f'/volume1/homes/{username}'
create_nas_folder(nas_path)
# 2. 設定配額
set_nas_quota(username, quota_gb=10)
# 3. 記錄到資料庫
drive = NetworkDrive(
employee_id=employee.id,
drive_name=f'{username}_personal',
drive_path=nas_path,
quota_gb=10,
webdav_url=f'https://nas.porscheworld.tw/webdav/{username}',
smb_path=f'\\\\10.1.0.30\\homes\\{username}'
)
db.add(drive)
return drive
```
---
## 📦 部署架構
### Docker Compose 服務
```yaml
services:
hr-portal-backend:
image: hr-portal-backend:latest
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://...
- KEYCLOAK_URL=https://auth.ease.taipei
- MAILSERVER_HOST=10.1.0.254
- NAS_HOST=10.1.0.30
labels:
- "traefik.enable=true"
- "traefik.http.routers.hr-api.rule=Host(`hr.porscheworld.tw`) && PathPrefix(`/api`)"
hr-portal-frontend:
image: hr-portal-frontend:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.hr-web.rule=Host(`hr.porscheworld.tw`)"
hr-portal-db:
image: postgres:16
volumes:
- hr-db-data:/var/lib/postgresql/data
```
### 網域配置
```
https://hr.porscheworld.tw - 前端應用
https://hr.porscheworld.tw/api - 後端 API
https://auth.ease.taipei - Keycloak SSO (已有)
```
---
## 🚀 開發流程
### 階段 1: 基礎設施
- ✅ 資料庫 Schema
- ✅ Keycloak Client 設定
- ✅ 後端 API 框架
### 階段 2: 核心功能
- ✅ SSO 認證整合
- ✅ 員工 CRUD
- ✅ 郵件帳號管理
- ✅ 網路硬碟管理
### 階段 3: 前端開發
- ✅ 管理端介面
- ✅ 個人端介面
- ✅ 儀表板
### 階段 4: 整合測試
- ✅ 端到端測試
- ✅ 效能測試
- ✅ 安全測試
### 階段 5: 部署上線
- ✅ Docker 容器化
- ✅ 生產環境部署
- ✅ 監控告警
---
## 📊 使用案例
### 案例 1: 新員工入職
```
HR 管理員操作:
1. 登入 HR Portal (SSO)
2. 點擊「新增員工」
3. 填寫基本資料
4. 系統自動:
- 在 Keycloak 創建帳號
- 創建郵件帳號 (user@ease.taipei)
- 配置網路硬碟 (10GB)
- 授予基本系統權限
5. 發送歡迎郵件給新員工
```
### 案例 2: 員工自助服務
```
員工操作:
1. 訪問 https://hr.porscheworld.tw
2. 用 Keycloak 帳號登入
3. 查看個人儀表板:
- 基本資料
- 郵箱使用量: 500MB / 1GB
- 硬碟使用量: 3GB / 10GB
- 可訪問系統列表
4. 更新個人聯絡資訊
5. 設定郵件自動回覆
```
### 案例 3: 員工離職
```
HR 管理員操作:
1. 搜尋員工
2. 點擊「離職處理」
3. 系統自動:
- 停用 Keycloak 帳號
- 停用郵件帳號 (或轉發)
- 備份個人硬碟
- 撤銷所有系統權限
4. 記錄審計日誌
```
---
**這個架構設計可以作為開發的藍圖,接下來我們可以開始實作!** 🚀