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>
7.7 KiB
7.7 KiB
員工到職流程測試指南 (v3.1)
測試環境
- Migration 版本: 0012 (已執行)
- 資料庫: hr_portal @ 10.1.0.20:5433
- 後端 API: http://localhost:10181/api/v1
- 前端: http://localhost:10180
API 端點清單
1. 個人化服務管理
# 取得所有可用服務
GET /api/v1/personal-services/services
# 查詢使用者已啟用服務
GET /api/v1/personal-services/users/{keycloak_user_id}/services
# 啟用單一服務
POST /api/v1/personal-services/users/{keycloak_user_id}/services
{
"service_id": 1,
"quota_gb": 20,
"quota_mb": 5120
}
# 批次啟用所有服務
POST /api/v1/personal-services/users/{keycloak_user_id}/services/batch-enable
{
"storage_quota_gb": 20,
"email_quota_mb": 5120
}
# 停用服務
DELETE /api/v1/personal-services/users/{keycloak_user_id}/services/{service_id}
2. 員工到職流程 (完整)
# 員工到職
POST /api/v1/emp-lifecycle/onboard
Content-Type: application/json
{
"resume_id": 1,
"keycloak_user_id": "550e8400-e29b-41d4-a716-446655440000",
"keycloak_username": "wang.ming",
"hire_date": "2026-02-20",
"departments": [
{
"department_id": 9,
"position": "資深工程師",
"membership_type": "permanent"
},
{
"department_id": 12,
"position": "專案經理",
"membership_type": "project"
}
],
"role_ids": [1, 2],
"storage_quota_gb": 20,
"email_quota_mb": 5120
}
預期回應:
{
"message": "Employee onboarded successfully",
"employee": {
"tenant_id": 1,
"seq_no": 1,
"tenant_emp_code": "PWD0001",
"keycloak_user_id": "550e8400-e29b-41d4-a716-446655440000",
"keycloak_username": "wang.ming",
"name": "王明",
"hire_date": "2026-02-20"
},
"summary": {
"departments_assigned": 2,
"roles_assigned": 2,
"services_enabled": 5
}
}
3. 查詢員工狀態
# 查詢完整狀態
GET /api/v1/emp-lifecycle/1/1/status
# 回應範例
{
"employee": {
"tenant_id": 1,
"seq_no": 1,
"tenant_emp_code": "PWD0001",
"name": "王明",
"keycloak_user_id": "550e8400-e29b-41d4-a716-446655440000",
"keycloak_username": "wang.ming",
"hire_date": "2026-02-20",
"resign_date": null,
"employment_status": "active",
"storage_quota_gb": 20,
"email_quota_mb": 5120
},
"departments": [
{
"department_id": 9,
"department_name": "玄鐵風能",
"position": "資深工程師",
"membership_type": "permanent",
"joined_at": "2026-02-20T10:00:00"
}
],
"roles": [
{
"role_id": 1,
"role_name": "HR管理員",
"role_code": "HR_ADMIN",
"assigned_at": "2026-02-20T10:00:00"
}
],
"services": [
{
"service_id": 1,
"service_name": "單一簽入",
"service_code": "SSO",
"quota_gb": null,
"quota_mb": null,
"enabled_at": "2026-02-20T10:00:00"
},
{
"service_id": 4,
"service_name": "網路硬碟",
"service_code": "Drive",
"quota_gb": 20,
"quota_mb": null,
"enabled_at": "2026-02-20T10:00:00"
}
]
}
4. 員工離職流程
# 員工離職
POST /api/v1/emp-lifecycle/1/1/offboard
# 回應範例
{
"message": "Employee offboarded successfully",
"employee": {
"tenant_emp_code": "PWD0001",
"resign_date": "2026-02-20"
},
"summary": {
"departments_removed": 2,
"roles_revoked": 2,
"services_disabled": 5
}
}
資料庫驗證查詢
檢查員工任用設定
SELECT
tenant_id,
seq_no,
tenant_emp_code,
tenant_keycloak_user_id,
tenant_keycloak_username,
hire_at,
storage_quota_gb,
email_quota_mb,
employment_status,
is_active
FROM tenant_emp_settings
WHERE tenant_id = 1;
檢查部門歸屬
SELECT
dm.id,
dm.employee_id,
dm.department_id,
d.name AS department_name,
dm.position,
dm.membership_type,
dm.joined_at,
dm.ended_at,
dm.assigned_by,
dm.is_active
FROM tenant_dept_members dm
LEFT JOIN tenant_departments d ON dm.department_id = d.id
WHERE dm.tenant_id = 1
ORDER BY dm.employee_id, dm.joined_at;
檢查角色分配
SELECT
ra.id,
ra.keycloak_user_id,
ra.role_id,
r.role_code,
r.role_name,
ra.assigned_at,
ra.revoked_at,
ra.assigned_by,
ra.is_active
FROM tenant_user_role_assignments ra
LEFT JOIN tenant_user_roles r ON ra.role_id = r.id
WHERE ra.tenant_id = 1
ORDER BY ra.keycloak_user_id, ra.assigned_at;
檢查個人化服務
SELECT
ss.id,
ss.tenant_keycloak_user_id,
ss.service_id,
s.service_name,
s.service_code,
ss.quota_gb,
ss.quota_mb,
ss.enabled_at,
ss.disabled_at,
ss.enabled_by,
ss.is_active
FROM tenant_emp_personal_service_settings ss
LEFT JOIN personal_services s ON ss.service_id = s.id
WHERE ss.tenant_id = 1
ORDER BY ss.tenant_keycloak_user_id, ss.service_id;
測試步驟
前置準備
-
確認資料庫狀態:
cd q:/porscheworld_develop/hr-portal/backend python -m alembic current # 應顯示: 0012 (head) -
啟動後端服務:
cd q:/porscheworld_develop/hr-portal START_BACKEND.bat -
確認服務運行:
curl http://localhost:10181/api/v1/docs
測試流程
Step 1: 建立測試用人員基本資料
-- 手動建立測試資料 (或透過 API)
INSERT INTO tenant_emp_resumes (tenant_id, name_tw, name_eng)
VALUES (1, '王明', 'Ming Wang')
RETURNING id;
-- 假設回傳 id = 1
Step 2: 執行到職流程
使用 Postman 或 curl:
curl -X POST http://localhost:10181/api/v1/emp-lifecycle/onboard \
-H "Content-Type: application/json" \
-d '{
"resume_id": 1,
"keycloak_user_id": "550e8400-e29b-41d4-a716-446655440000",
"keycloak_username": "wang.ming",
"hire_date": "2026-02-20",
"departments": [
{"department_id": 1, "position": "工程師"}
],
"role_ids": [1],
"storage_quota_gb": 20,
"email_quota_mb": 5120
}'
Step 3: 驗證資料
# 查詢狀態
curl http://localhost:10181/api/v1/emp-lifecycle/1/1/status
Step 4: 執行離職流程
curl -X POST http://localhost:10181/api/v1/emp-lifecycle/1/1/offboard
預期結果
到職後應建立的資料
- ✅
tenant_emp_settings: 1 筆記錄 - ✅
tenant_dept_members: N 筆記錄(依 departments 數量) - ✅
tenant_user_role_assignments: N 筆記錄(依 role_ids 數量) - ✅
tenant_emp_personal_service_settings: 5 筆記錄(所有服務)
離職後應更新的資料
- ✅
tenant_emp_settings.employment_status= 'resigned' - ✅
tenant_emp_settings.resign_date= 當天日期 - ✅
tenant_dept_members.is_active= false,ended_at= 當前時間 - ✅
tenant_user_role_assignments.is_active= false,revoked_at= 當前時間 - ✅
tenant_emp_personal_service_settings.is_active= false,disabled_at= 當前時間
故障排除
問題 1: Port 被占用
# Windows
netstat -ano | findstr :10181
taskkill /PID <PID> /F
問題 2: 資料庫連線失敗
檢查連線字串:
postgresql://admin:DC1qaz2wsx@10.1.0.20:5433/hr_portal
問題 3: Migration 版本不對
cd q:/porscheworld_develop/hr-portal/backend
python -m alembic upgrade head
注意事項
⚠️ 重要:
- 此為測試環境,請勿在正式資料上測試
- 測試前請備份資料庫
- Keycloak User ID 必須是有效的 UUID 格式
- 部門 ID 和角色 ID 必須在資料庫中存在
測試文件版本: v1.0 建立日期: 2026-02-20 適用架構: HR Portal v3.1 (多租戶 + 關聯表)