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>
This commit is contained in:
2026-02-23 20:12:43 +08:00
commit 360533393f
386 changed files with 70353 additions and 0 deletions

View File

@@ -0,0 +1,322 @@
-- =========================================
-- HR Portal 初始化系統資料表
-- 根據 app/models/installation.py 建立完整表結構
-- =========================================
-- 1. installation_sessions (安裝會話)
DROP TABLE IF EXISTS installation_sessions CASCADE;
CREATE TABLE installation_sessions (
id SERIAL PRIMARY KEY,
tenant_id INTEGER,
session_name VARCHAR(200),
environment VARCHAR(20), -- development/testing/production
-- 狀態追蹤
started_at TIMESTAMP DEFAULT NOW(),
completed_at TIMESTAMP,
status VARCHAR(20) DEFAULT 'in_progress', -- in_progress/completed/failed/paused
-- 進度統計
total_checklist_items INTEGER,
passed_checklist_items INTEGER DEFAULT 0,
failed_checklist_items INTEGER DEFAULT 0,
total_steps INTEGER,
completed_steps INTEGER DEFAULT 0,
failed_steps INTEGER DEFAULT 0,
executed_by VARCHAR(100),
-- 存取控制
is_locked BOOLEAN DEFAULT FALSE,
locked_at TIMESTAMP,
locked_by VARCHAR(100),
lock_reason VARCHAR(200),
is_unlocked BOOLEAN DEFAULT FALSE,
unlocked_at TIMESTAMP,
unlocked_by VARCHAR(100),
unlock_reason VARCHAR(200),
unlock_expires_at TIMESTAMP,
last_viewed_at TIMESTAMP,
last_viewed_by VARCHAR(100),
view_count INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW()
);
-- 2. installation_checklist_items (檢查項目定義)
DROP TABLE IF EXISTS installation_checklist_items CASCADE;
CREATE TABLE installation_checklist_items (
id SERIAL PRIMARY KEY,
category VARCHAR(50) NOT NULL, -- hardware/network/software/container/security
item_code VARCHAR(100) UNIQUE NOT NULL,
item_name VARCHAR(200) NOT NULL,
check_type VARCHAR(50) NOT NULL, -- command/api/config/manual
check_command TEXT,
expected_value TEXT,
min_requirement TEXT,
recommended_value TEXT,
is_required BOOLEAN DEFAULT TRUE,
sequence_order INTEGER NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- 3. installation_checklist_results (檢查結果)
DROP TABLE IF EXISTS installation_checklist_results CASCADE;
CREATE TABLE installation_checklist_results (
id SERIAL PRIMARY KEY,
tenant_id INTEGER,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE CASCADE,
checklist_item_id INTEGER REFERENCES installation_checklist_items(id) ON DELETE CASCADE NOT NULL,
status VARCHAR(20) NOT NULL, -- pass/fail/warning/pending/skip
actual_value TEXT,
checked_at TIMESTAMP,
checked_by VARCHAR(100),
auto_checked BOOLEAN DEFAULT FALSE,
remarks TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 4. installation_steps (安裝步驟定義)
DROP TABLE IF EXISTS installation_steps CASCADE;
CREATE TABLE installation_steps (
id SERIAL PRIMARY KEY,
step_code VARCHAR(50) UNIQUE NOT NULL,
step_name VARCHAR(200) NOT NULL,
phase VARCHAR(20) NOT NULL, -- phase1/phase2/...
sequence_order INTEGER NOT NULL,
description TEXT,
execution_type VARCHAR(50), -- auto/manual/script
execution_script TEXT,
depends_on_steps VARCHAR[], -- 依賴的步驟代碼
is_required BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT NOW()
);
-- 5. installation_logs (安裝執行記錄)
DROP TABLE IF EXISTS installation_logs CASCADE;
CREATE TABLE installation_logs (
id SERIAL PRIMARY KEY,
tenant_id INTEGER,
step_id INTEGER REFERENCES installation_steps(id) ON DELETE CASCADE NOT NULL,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL, -- pending/running/success/failed/skipped
started_at TIMESTAMP,
completed_at TIMESTAMP,
executed_by VARCHAR(100),
execution_method VARCHAR(50), -- manual/auto/api/script
result_data JSONB,
error_message TEXT,
retry_count INTEGER DEFAULT 0,
remarks TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 6. installation_tenant_info (租戶初始化資訊)
DROP TABLE IF EXISTS installation_tenant_info CASCADE;
CREATE TABLE installation_tenant_info (
id SERIAL PRIMARY KEY,
tenant_id INTEGER UNIQUE,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE SET NULL,
-- 公司基本資訊
company_name VARCHAR(200),
company_name_en VARCHAR(200),
tenant_code VARCHAR(50),
tenant_prefix VARCHAR(10),
tax_id VARCHAR(50),
industry VARCHAR(100),
company_size VARCHAR(20), -- small/medium/large
-- 聯絡資訊
tel VARCHAR(20),
phone VARCHAR(50),
fax VARCHAR(50),
email VARCHAR(200),
website VARCHAR(200),
add TEXT,
address TEXT,
address_en TEXT,
-- 郵件網域設定
domain_set INTEGER DEFAULT 2, -- 1=組織網域, 2=部門網域
domain VARCHAR(100),
-- 負責人資訊
representative_name VARCHAR(100),
representative_title VARCHAR(100),
representative_email VARCHAR(200),
representative_phone VARCHAR(50),
-- 系統管理員資訊
admin_employee_id VARCHAR(50),
admin_username VARCHAR(100),
admin_legal_name VARCHAR(100),
admin_english_name VARCHAR(100),
admin_email VARCHAR(200),
admin_phone VARCHAR(50),
-- 初始設定
default_language VARCHAR(10) DEFAULT 'zh-TW',
timezone VARCHAR(50) DEFAULT 'Asia/Taipei',
date_format VARCHAR(20) DEFAULT 'YYYY-MM-DD',
currency VARCHAR(10) DEFAULT 'TWD',
-- 狀態追蹤
is_completed BOOLEAN DEFAULT FALSE,
completed_at TIMESTAMP,
completed_by VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 7. installation_mail_domain_setting (郵件網域設定)
DROP TABLE IF EXISTS installation_mail_domain_setting CASCADE;
CREATE TABLE installation_mail_domain_setting (
id SERIAL PRIMARY KEY,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE CASCADE NOT NULL,
domain_set INTEGER NOT NULL, -- 1=組織網域, 2=部門網域
domain VARCHAR(100), -- 組織網域domain_set=1 時使用)
created_at TIMESTAMP DEFAULT NOW()
);
-- 8. installation_department_setup (部門架構設定)
DROP TABLE IF EXISTS installation_department_setup CASCADE;
CREATE TABLE installation_department_setup (
id SERIAL PRIMARY KEY,
tenant_id INTEGER,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE CASCADE,
department_code VARCHAR(50) NOT NULL,
department_name VARCHAR(200) NOT NULL,
department_name_en VARCHAR(200),
email_domain VARCHAR(100),
parent_code VARCHAR(50),
depth INTEGER DEFAULT 0,
manager_name VARCHAR(100),
is_created BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW()
);
-- 9. temporary_passwords (臨時密碼)
DROP TABLE IF EXISTS temporary_passwords CASCADE;
CREATE TABLE temporary_passwords (
id SERIAL PRIMARY KEY,
tenant_id INTEGER,
employee_id INTEGER,
username VARCHAR(100) NOT NULL,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE SET NULL,
-- 密碼資訊
password_hash VARCHAR(255) NOT NULL,
plain_password VARCHAR(100),
password_method VARCHAR(20), -- auto/manual
is_temporary BOOLEAN DEFAULT TRUE,
must_change_on_login BOOLEAN DEFAULT TRUE,
-- 有效期限
created_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP,
-- 使用狀態
is_used BOOLEAN DEFAULT FALSE,
used_at TIMESTAMP,
first_login_at TIMESTAMP,
password_changed_at TIMESTAMP,
-- 查看控制
is_viewable BOOLEAN DEFAULT TRUE,
viewable_until TIMESTAMP,
view_count INTEGER DEFAULT 0,
last_viewed_at TIMESTAMP,
first_viewed_at TIMESTAMP,
-- 明文密碼清除記錄
plain_password_cleared_at TIMESTAMP,
cleared_reason VARCHAR(100)
);
-- 10. installation_access_logs (存取審計日誌)
DROP TABLE IF EXISTS installation_access_logs CASCADE;
CREATE TABLE installation_access_logs (
id SERIAL PRIMARY KEY,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE CASCADE NOT NULL,
action VARCHAR(50) NOT NULL, -- lock/unlock/view/download_pdf
action_by VARCHAR(100),
action_method VARCHAR(50), -- database/api/system
ip_address VARCHAR(50),
user_agent TEXT,
access_granted BOOLEAN,
deny_reason VARCHAR(200),
sensitive_data_accessed VARCHAR[],
created_at TIMESTAMP DEFAULT NOW()
);
-- 11. installation_environment_config (環境配置記錄)
DROP TABLE IF EXISTS installation_environment_config CASCADE;
CREATE TABLE installation_environment_config (
id SERIAL PRIMARY KEY,
session_id INTEGER REFERENCES installation_sessions(id) ON DELETE SET NULL,
config_key VARCHAR(100) UNIQUE NOT NULL,
config_value TEXT,
config_category VARCHAR(50) NOT NULL, -- redis/database/keycloak/mailserver/nextcloud/traefik
is_sensitive BOOLEAN DEFAULT FALSE,
is_configured BOOLEAN DEFAULT FALSE,
configured_at TIMESTAMP,
configured_by VARCHAR(100),
description TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_env_config_key ON installation_environment_config(config_key);
CREATE INDEX idx_env_config_category ON installation_environment_config(config_category);
-- 12. installation_system_status (系統狀態記錄)
DROP TABLE IF EXISTS installation_system_status CASCADE;
CREATE TABLE installation_system_status (
id SERIAL PRIMARY KEY,
current_phase VARCHAR(20) NOT NULL, -- initialization/operational/transition
previous_phase VARCHAR(20),
phase_changed_at TIMESTAMP,
phase_changed_by VARCHAR(100),
phase_change_reason TEXT,
-- Initialization 階段資訊
initialized_at TIMESTAMP,
initialized_by VARCHAR(100),
initialization_completed BOOLEAN DEFAULT FALSE,
-- Operational 階段資訊
last_health_check_at TIMESTAMP,
health_check_status VARCHAR(20), -- healthy/degraded/unhealthy
operational_since TIMESTAMP,
-- Transition 階段資訊
transition_started_at TIMESTAMP,
transition_approved_by VARCHAR(100),
env_db_consistent BOOLEAN,
consistency_checked_at TIMESTAMP,
inconsistencies TEXT,
-- 系統鎖定
is_locked BOOLEAN DEFAULT FALSE,
locked_at TIMESTAMP,
locked_by VARCHAR(100),
lock_reason VARCHAR(200),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_system_status_phase ON installation_system_status(current_phase);
-- =========================================
-- 初始化系統狀態
-- =========================================
INSERT INTO installation_system_status (current_phase, initialization_completed)
VALUES ('initialization', FALSE);
COMMIT;