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>
512 lines
12 KiB
Markdown
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. 記錄審計日誌
|
|
```
|
|
|
|
---
|
|
|
|
**這個架構設計可以作為開發的藍圖,接下來我們可以開始實作!** 🚀
|