Files
hr-portal/scripts/insert-test-data.sql
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

394 lines
7.9 KiB
SQL

-- ====================================
-- HR Portal - 測試資料
-- ====================================
-- 用途: 插入測試資料以驗證系統功能
-- ====================================
-- 檢查事業部資料
SELECT '=== 事業部資料 ===' as info;
SELECT id, code, name, name_en FROM business_units ORDER BY id;
-- 檢查部門資料
SELECT '=== 部門資料 ===' as info;
SELECT id, business_unit_id, code, name, name_en FROM divisions ORDER BY id;
-- 插入測試員工
INSERT INTO employees (
employee_id,
username,
first_name,
last_name,
chinese_name,
email,
mobile,
business_unit_id,
division_id,
position,
job_title,
job_level,
employment_type,
hire_date,
status
) VALUES
-- 管理層
(
'E0001',
'porsche.chen',
'Porsche',
'Chen',
'陳博駿',
'porsche.chen@porscheworld.tw',
'0912-345-678',
4, -- 管理部門
10, -- 資訊部
'CTO',
'技術長',
'C-Level',
'full-time',
'2020-01-01',
'active'
),
-- 智能研發服務 - 軟體工程師
(
'E1001',
'alice.wang',
'Alice',
'Wang',
'王小華',
'alice.wang@lab.taipei',
'0923-456-789',
3, -- 智能研發服務
7, -- 軟體研發部
'Frontend Developer',
'前端工程師',
'Engineer',
'full-time',
'2024-03-01',
'active'
),
(
'E1002',
'bob.chen',
'Bob',
'Chen',
'陳大明',
'bob.chen@lab.taipei',
'0934-567-890',
3, -- 智能研發服務
7, -- 軟體研發部
'Backend Developer',
'後端工程師',
'Senior',
'full-time',
'2023-06-15',
'active'
),
-- 玄鐵風能授權服務
(
'E2001',
'charlie.lin',
'Charlie',
'Lin',
'林志明',
'charlie.lin@ease.taipei',
'0945-678-901',
1, -- 玄鐵風能
1, -- 技術授權部
'Sales Manager',
'業務經理',
'Manager',
'full-time',
'2022-08-20',
'active'
),
-- 國際碳權申請服務
(
'E3001',
'diana.wu',
'Diana',
'Wu',
'吳雅婷',
'diana.wu@ease.taipei',
'0956-789-012',
2, -- 國際碳權
4, -- 碳權申請部
'Carbon Credit Consultant',
'碳權顧問',
'Senior',
'full-time',
'2023-02-10',
'active'
)
ON CONFLICT (employee_id) DO NOTHING;
-- 插入測試郵件帳號
INSERT INTO email_accounts (
employee_id,
email_address,
mailbox_quota_mb,
is_active
)
SELECT
id,
email,
CASE
WHEN job_level = 'C-Level' THEN 5120 -- 5GB
WHEN job_level = 'Manager' THEN 2048 -- 2GB
ELSE 1024 -- 1GB
END,
TRUE
FROM employees
WHERE email IS NOT NULL
ON CONFLICT (email_address) DO NOTHING;
-- 插入測試網路硬碟
INSERT INTO network_drives (
employee_id,
drive_name,
drive_path,
quota_gb,
webdav_url,
smb_path,
is_active
)
SELECT
id,
username || '_personal',
'/volume1/homes/' || username,
CASE
WHEN job_level = 'C-Level' THEN 50
WHEN job_level = 'VP' THEN 30
WHEN job_level = 'Director' THEN 30
WHEN job_level = 'Manager' THEN 20
WHEN job_level = 'Senior' THEN 15
ELSE 10
END,
'https://nas.porscheworld.tw/webdav/' || username,
'\\10.1.0.30\homes\' || username,
TRUE
FROM employees
ON CONFLICT DO NOTHING;
-- 插入測試系統權限
INSERT INTO system_permissions (
employee_id,
system_name,
system_url,
access_level,
is_active,
granted_by
)
SELECT
id,
system,
url,
access_level,
TRUE,
'system'
FROM employees
CROSS JOIN (
VALUES
('HR Portal', 'https://hr.porscheworld.tw', 'user'),
('Webmail', 'https://webmail.porscheworld.tw', 'user')
) AS systems(system, url, access_level)
WHERE status = 'active'
ON CONFLICT (employee_id, system_name) DO NOTHING;
-- 為研發人員新增額外權限
INSERT INTO system_permissions (
employee_id,
system_name,
system_url,
access_level,
is_active,
granted_by
)
SELECT
id,
system,
url,
access_level,
TRUE,
'system'
FROM employees
CROSS JOIN (
VALUES
('Gitea', 'https://git.lab.taipei', 'developer'),
('Portainer', 'https://portainer.porscheworld.tw', 'user')
) AS dev_systems(system, url, access_level)
WHERE division_id IN (7, 8, 9) -- 研發部門
AND status = 'active'
ON CONFLICT (employee_id, system_name) DO NOTHING;
-- 插入測試專案
INSERT INTO projects (
business_unit_id,
project_code,
project_name,
description,
client_name,
status,
project_manager_id,
start_date,
end_date,
budget_amount,
budget_currency
) VALUES
(
3, -- 智能研發
'PRJ-2024-001',
'HR Portal 開發專案',
'企業人資管理系統開發',
'內部專案',
'active',
(SELECT id FROM employees WHERE username = 'porsche.chen'),
'2024-01-15',
'2024-06-30',
1000000.00,
'TWD'
),
(
1, -- 玄鐵風能
'PRJ-2024-002',
'台中風場評估案',
'台中離岸風場技術評估與授權',
'台灣風電公司',
'active',
(SELECT id FROM employees WHERE username = 'charlie.lin'),
'2024-02-01',
'2024-08-31',
5000000.00,
'TWD'
),
(
2, -- 國際碳權
'PRJ-2024-003',
'某企業碳盤查專案',
'ISO 14064-1 組織型溫室氣體盤查',
'科技公司 A',
'planning',
(SELECT id FROM employees WHERE username = 'diana.wu'),
'2024-03-01',
'2024-12-31',
800000.00,
'TWD'
)
ON CONFLICT (project_code) DO NOTHING;
-- 插入專案成員
INSERT INTO project_members (
project_id,
employee_id,
role,
allocation_percentage
)
SELECT
p.id,
e.id,
member.role,
member.allocation
FROM projects p
CROSS JOIN LATERAL (
VALUES
((SELECT id FROM employees WHERE username = 'porsche.chen'), 'project-manager', 50),
((SELECT id FROM employees WHERE username = 'alice.wang'), 'developer', 80),
((SELECT id FROM employees WHERE username = 'bob.chen'), 'developer', 100)
) AS member(employee_id, role, allocation)
JOIN employees e ON e.id = member.employee_id
WHERE p.project_code = 'PRJ-2024-001'
ON CONFLICT (project_id, employee_id) DO NOTHING;
-- ====================================
-- 查詢驗證資料
-- ====================================
SELECT '=== 員工資料 ===' as info;
SELECT
employee_id,
username,
chinese_name,
email,
position,
job_level,
status
FROM employees
ORDER BY employee_id;
SELECT '=== 郵件帳號 ===' as info;
SELECT
e.username,
ea.email_address,
ea.mailbox_quota_mb || 'MB' as quota,
ea.is_active
FROM email_accounts ea
JOIN employees e ON ea.employee_id = e.id
ORDER BY e.employee_id;
SELECT '=== 網路硬碟 ===' as info;
SELECT
e.username,
nd.drive_name,
nd.quota_gb || 'GB' as quota,
nd.is_active
FROM network_drives nd
JOIN employees e ON nd.employee_id = e.id
ORDER BY e.employee_id;
SELECT '=== 系統權限 ===' as info;
SELECT
e.username,
sp.system_name,
sp.access_level,
sp.is_active
FROM system_permissions sp
JOIN employees e ON sp.employee_id = e.id
ORDER BY e.username, sp.system_name;
SELECT '=== 專案資訊 ===' as info;
SELECT
p.project_code,
p.project_name,
p.status,
e.chinese_name as project_manager,
COUNT(pm.id) as member_count
FROM projects p
LEFT JOIN employees e ON p.project_manager_id = e.id
LEFT JOIN project_members pm ON p.id = pm.project_id
GROUP BY p.id, p.project_code, p.project_name, p.status, e.chinese_name
ORDER BY p.project_code;
-- 統計資訊
SELECT '=== 統計資訊 ===' as info;
SELECT
'員工總數' as metric,
COUNT(*) as count
FROM employees
UNION ALL
SELECT
'活躍員工',
COUNT(*)
FROM employees
WHERE status = 'active'
UNION ALL
SELECT
'郵件帳號',
COUNT(*)
FROM email_accounts
UNION ALL
SELECT
'網路硬碟',
COUNT(*)
FROM network_drives
UNION ALL
SELECT
'活躍專案',
COUNT(*)
FROM projects
WHERE status = 'active';
SELECT '=== 資料插入完成 ===' as info;