commit 360533393f6c449a50cbf9ce59712d5867cfce42 Author: Porsche Chen Date: Mon Feb 23 20:12:43 2026 +0800 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 diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml new file mode 100644 index 0000000..8c83d41 --- /dev/null +++ b/.gitea/workflows/ci-cd.yml @@ -0,0 +1,294 @@ +name: HR Portal CI/CD + +on: + push: + branches: + - main # 生產環境 + - dev # 測試環境 + pull_request: + branches: + - main + - dev + +env: + REGISTRY: git.lab.taipei + IMAGE_NAME_BACKEND: porscheworld/hr-portal-backend + IMAGE_NAME_FRONTEND: porscheworld/hr-portal-frontend + +jobs: + # ============================================== + # 測試階段 - 後端 + # ============================================== + test-backend: + name: Test Backend (FastAPI) + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_DB: hr_portal_test + POSTGRES_USER: test_user + POSTGRES_PASSWORD: test_password + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install Dependencies + working-directory: ./backend + run: | + pip install --upgrade pip + pip install -r requirements.txt + + - name: Run Tests with Coverage + working-directory: ./backend + env: + DATABASE_HOST: localhost + DATABASE_PORT: 5432 + DATABASE_NAME: hr_portal_test + DATABASE_USER: test_user + DATABASE_PASSWORD: test_password + run: | + pytest tests/ --cov=app --cov-report=term-missing --cov-report=xml + + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v3 + with: + file: ./backend/coverage.xml + flags: backend + name: backend-coverage + + # ============================================== + # 測試階段 - 前端 + # ============================================== + test-frontend: + name: Test Frontend (Next.js) + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Node.js 18 + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: ./frontend/package-lock.json + + - name: Install Dependencies + working-directory: ./frontend + run: npm ci + + - name: Run Lint + working-directory: ./frontend + run: npm run lint + + - name: Run Type Check + working-directory: ./frontend + run: npx tsc --noEmit + + - name: Build + working-directory: ./frontend + run: npm run build + + # ============================================== + # 建置與推送映像 - 後端 + # ============================================== + build-backend: + name: Build Backend Image + needs: test-backend + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.GITEA_USERNAME }} + password: ${{ secrets.GITEA_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }} + tags: | + type=ref,event=branch + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and Push + uses: docker/build-push-action@v5 + with: + context: ./backend + file: ./backend/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:buildcache,mode=max + + # ============================================== + # 建置與推送映像 - 前端 + # ============================================== + build-frontend: + name: Build Frontend Image + needs: test-frontend + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.GITEA_USERNAME }} + password: ${{ secrets.GITEA_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }} + tags: | + type=ref,event=branch + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and Push + uses: docker/build-push-action@v5 + with: + context: ./frontend + file: ./frontend/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:buildcache,mode=max + + # ============================================== + # 部署到測試環境 (dev 分支) + # ============================================== + deploy-testing: + name: Deploy to Testing Environment + needs: [build-backend, build-frontend] + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/dev' + environment: + name: testing + url: https://test.hr.ease.taipei + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Deploy to Testing Server + uses: appleboy/ssh-action@v1.0.0 + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + port: 22 + script: | + cd /opt/deployments/hr-portal-test + + # 拉取最新映像 + docker-compose -f docker-compose.prod.yml pull + + # 重啟服務 + docker-compose -f docker-compose.prod.yml up -d + + # 清理舊映像 + docker image prune -f + + # 檢查服務狀態 + docker-compose -f docker-compose.prod.yml ps + + # ============================================== + # 部署到生產環境 (main 分支) + # ============================================== + deploy-production: + name: Deploy to Production Environment + needs: [build-backend, build-frontend] + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + environment: + name: production + url: https://hr.ease.taipei + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Deploy to Production Server + uses: appleboy/ssh-action@v1.0.0 + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + port: 22 + script: | + cd /opt/deployments/hr-portal-prod + + # 拉取最新映像 + docker-compose -f docker-compose.prod.yml pull + + # 執行資料庫備份 + docker exec hr-portal-postgres-prod pg_dump -U hr_admin hr_portal | gzip > backup-$(date +%Y%m%d-%H%M%S).sql.gz + + # 滾動更新 (零停機部署) + docker-compose -f docker-compose.prod.yml up -d --no-deps --build backend + sleep 10 + docker-compose -f docker-compose.prod.yml up -d --no-deps --build frontend + + # 清理舊映像 + docker image prune -f + + # 檢查服務狀態 + docker-compose -f docker-compose.prod.yml ps + + # 健康檢查 + curl -f https://hr-api.ease.taipei/health || exit 1 + + # ============================================== + # 通知 + # ============================================== + notify: + name: Send Notification + needs: [deploy-testing, deploy-production] + runs-on: ubuntu-latest + if: always() + + steps: + - name: Send Notification + run: | + echo "Deployment completed for branch: ${{ github.ref_name }}" + # TODO: 整合 Email 或 Slack 通知 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60bc0b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,70 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +venv/ +venv311/ +ENV/ +env/ + +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# Next.js +.next/ +out/ + +# Environment +.env +.env.local +.env.*.local + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ + +# Database +*.db +*.sqlite +*.sqlite3 + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# Alembic +alembic/versions/*.pyc diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..1b3ee68 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,511 @@ +# 🏢 人資管理系統架構設計 + +## 📋 系統概述 + +**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. 記錄審計日誌 +``` + +--- + +**這個架構設計可以作為開發的藍圖,接下來我們可以開始實作!** 🚀 diff --git a/BUSINESS-STRUCTURE.md b/BUSINESS-STRUCTURE.md new file mode 100644 index 0000000..2f06f8e --- /dev/null +++ b/BUSINESS-STRUCTURE.md @@ -0,0 +1,543 @@ +# 🏢 公司組織架構與業務配置 + +## 公司概況 + +**Porsche World** - 智慧能源與碳權管理解決方案提供商 + +--- + +## 🎯 業務部門 + +### 1. 玄鐵風能授權服務事業部 +**Business Unit**: Wind Energy Licensing + +#### 業務內容 +- 風力發電技術授權 +- 風能系統設計與諮詢 +- 風場評估與規劃 +- 技術培訓服務 + +#### 組織架構 +``` +玄鐵風能授權服務事業部 +├── 技術授權部 +│ ├── 授權商務組 +│ └── 技術支援組 +├── 風場評估部 +│ ├── 資源評估組 +│ └── 場域規劃組 +└── 客戶服務部 + ├── 技術培訓組 + └── 售後服務組 +``` + +#### 主要客戶類型 +- 風電開發商 +- 能源公司 +- 政府機構 +- 研究機構 + +--- + +### 2. 國際碳權申請服務事業部 +**Business Unit**: Carbon Credit Services + +#### 業務內容 +- 碳權申請諮詢 +- 碳足跡盤查 +- 碳減排專案開發 +- 碳權交易媒合 +- 國際碳權認證 (CDM, VCS, Gold Standard) + +#### 組織架構 +``` +國際碳權申請服務事業部 +├── 碳權申請部 +│ ├── 專案開發組 +│ └── 文件審查組 +├── 碳盤查部 +│ ├── 盤查執行組 +│ └── 數據分析組 +└── 碳交易部 + ├── 市場分析組 + └── 交易媒合組 +``` + +#### 主要服務 +- ISO 14064 碳盤查 +- PAS 2060 碳中和認證 +- 碳權專案開發 +- 碳權買賣仲介 + +--- + +### 3. 智能研發服務事業部 +**Business Unit**: Smart R&D Services + +#### 業務內容 +- AI/ML 解決方案開發 +- IoT 智能監控系統 +- 能源管理系統 (EMS) +- 數據分析平台 +- 系統整合服務 + +#### 組織架構 +``` +智能研發服務事業部 +├── 軟體研發部 +│ ├── 前端開發組 +│ ├── 後端開發組 +│ └── AI/ML 組 +├── 硬體研發部 +│ ├── IoT 設備組 +│ └── 系統整合組 +└── 產品管理部 + ├── 產品企劃組 + └── 專案管理組 +``` + +#### 技術領域 +- Python, FastAPI, React +- TensorFlow, PyTorch +- LoRaWAN, MQTT +- Time-series Database +- Edge Computing + +--- + +## 🏗️ 公司組織架構 + +### 完整組織圖 + +``` +Porsche World +│ +├── 執行長室 +│ └── 特助 +│ +├── 管理部門 +│ ├── 人力資源部 +│ │ ├── 招募組 +│ │ ├── 訓練發展組 +│ │ └── 薪酬福利組 +│ ├── 財務部 +│ │ ├── 會計組 +│ │ └── 財務分析組 +│ ├── 行政部 +│ │ ├── 總務組 +│ │ └── 採購組 +│ └── 資訊部 (IT) +│ ├── 系統維運組 +│ ├── 資安組 +│ └── 開發支援組 +│ +├── 業務部門 +│ ├── 玄鐵風能授權服務事業部 +│ │ ├── 技術授權部 +│ │ ├── 風場評估部 +│ │ └── 客戶服務部 +│ │ +│ ├── 國際碳權申請服務事業部 +│ │ ├── 碳權申請部 +│ │ ├── 碳盤查部 +│ │ └── 碳交易部 +│ │ +│ └── 智能研發服務事業部 +│ ├── 軟體研發部 +│ ├── 硬體研發部 +│ └── 產品管理部 +│ +└── 營運支援 + ├── 法務部 + ├── 品質管理部 + └── 業務發展部 +``` + +--- + +## 👥 職位體系 + +### 管理職 +- **C-Level**: CEO, CTO, CFO, COO +- **VP**: 副總經理 +- **Director**: 部門總監 +- **Manager**: 經理 +- **Supervisor**: 主管 + +### 專業職 +- **Principal**: 首席專家 +- **Senior**: 資深專員 +- **Staff**: 專員 +- **Associate**: 助理專員 +- **Junior**: 初階專員 + +### 技術職 (研發部門) +- **Architect**: 架構師 +- **Tech Lead**: 技術主管 +- **Senior Engineer**: 資深工程師 +- **Engineer**: 工程師 +- **Junior Engineer**: 初階工程師 + +--- + +## 📧 電子郵件命名規則 + +### 網域配置 +- **porscheworld.tw**: 對外官方信箱 +- **ease.taipei**: 業務與專案使用 +- **lab.taipei**: 技術研發使用 + +### 部門郵箱 + +#### 管理部門 (@porscheworld.tw) +``` +admin@porscheworld.tw - 管理部 +hr@porscheworld.tw - 人資部 +finance@porscheworld.tw - 財務部 +it@porscheworld.tw - 資訊部 +legal@porscheworld.tw - 法務部 +``` + +#### 玄鐵風能授權服務 (@ease.taipei) +``` +wind@ease.taipei - 部門總信箱 +wind-licensing@ease.taipei - 技術授權部 +wind-assessment@ease.taipei - 風場評估部 +wind-service@ease.taipei - 客戶服務部 +``` + +#### 國際碳權申請服務 (@ease.taipei) +``` +carbon@ease.taipei - 部門總信箱 +carbon-apply@ease.taipei - 碳權申請部 +carbon-audit@ease.taipei - 碳盤查部 +carbon-trade@ease.taipei - 碳交易部 +``` + +#### 智能研發服務 (@lab.taipei) +``` +dev@lab.taipei - 研發部總信箱 +software@lab.taipei - 軟體研發部 +hardware@lab.taipei - 硬體研發部 +product@lab.taipei - 產品管理部 +git@lab.taipei - Gitea 通知 +ci@lab.taipei - CI/CD 通知 +``` + +### 個人郵箱規則 +``` +格式: 名.姓@網域 + +範例: +john.doe@ease.taipei - 業務人員 +jane.smith@lab.taipei - 研發人員 +michael.chen@porscheworld.tw - 管理人員 +``` + +--- + +## 💾 網路硬碟配置 + +### 部門共享空間 + +#### 玄鐵風能授權服務 (NAS) +``` +/volume1/departments/wind-energy/ +├── /projects/ - 專案資料 +├── /technical-docs/ - 技術文件 +├── /contracts/ - 合約文件 +└── /training-materials/ - 培訓教材 +``` + +#### 國際碳權申請服務 (NAS) +``` +/volume1/departments/carbon-credit/ +├── /applications/ - 申請文件 +├── /audits/ - 盤查報告 +├── /certifications/ - 認證文件 +└── /trading-records/ - 交易記錄 +``` + +#### 智能研發服務 (NAS) +``` +/volume1/departments/smart-rd/ +├── /source-code/ - 原始碼 (輔助備份) +├── /documentation/ - 技術文件 +├── /design-files/ - 設計檔案 +└── /test-data/ - 測試資料 +``` + +### 個人空間配額 + +| 職級 | 配額 | 說明 | +|------|------|------| +| C-Level | 50 GB | 高階主管 | +| VP/Director | 30 GB | 中階主管 | +| Manager | 20 GB | 經理級 | +| 一般員工 | 10 GB | 專員、工程師 | +| 約聘/臨時 | 5 GB | 約聘人員 | + +--- + +## 🔐 系統權限配置 + +### 基本權限 (所有員工) +- ✅ Keycloak SSO 帳號 +- ✅ 電子郵件 +- ✅ 網路硬碟 (個人空間) +- ✅ HR Portal (個人資訊) +- ✅ Webmail 訪問 + +### 部門權限 + +#### 玄鐵風能授權服務 +- ✅ 專案管理系統 +- ✅ 客戶關係管理 (CRM) +- ✅ 文件管理系統 +- ✅ 部門共享硬碟 + +#### 國際碳權申請服務 +- ✅ 碳權管理平台 +- ✅ 盤查數據系統 +- ✅ 認證文件庫 +- ✅ 部門共享硬碟 + +#### 智能研發服務 +- ✅ Gitea (代碼管理) +- ✅ Drone CI/CD +- ✅ Portainer (容器管理) +- ✅ 開發工具授權 +- ✅ 部門共享硬碟 + +### 管理權限 + +#### 人資部 +- ✅ HR Portal (管理端) +- ✅ 薪資系統 +- ✅ 考勤系統 +- ✅ 所有員工資料 + +#### 資訊部 +- ✅ Keycloak 管理 +- ✅ Traefik 管理 +- ✅ 伺服器管理 +- ✅ 所有系統管理權限 + +#### 財務部 +- ✅ ERP 系統 +- ✅ 財務報表系統 +- ✅ 發票系統 + +--- + +## 📊 HR Portal 資料庫擴充 + +### 新增欄位設計 + +#### employees 表擴充 + +```sql +ALTER TABLE employees ADD COLUMN IF NOT EXISTS + business_unit VARCHAR(50), -- 事業部: wind-energy, carbon-credit, smart-rd + division VARCHAR(100), -- 部門: 技術授權部, 軟體研發部 等 + team VARCHAR(100), -- 組別: 授權商務組, 前端開發組 等 + job_level VARCHAR(20), -- 職級: C-Level, VP, Director, Manager 等 + employee_type VARCHAR(20); -- 員工類型: full-time, part-time, contractor, intern + +-- 索引 +CREATE INDEX idx_employees_business_unit ON employees(business_unit); +CREATE INDEX idx_employees_division ON employees(division); +``` + +#### business_units 表 (新增) + +```sql +CREATE TABLE business_units ( + id SERIAL PRIMARY KEY, + code VARCHAR(50) UNIQUE NOT NULL, + name VARCHAR(100) NOT NULL, + name_en VARCHAR(100), + description TEXT, + manager_id INTEGER REFERENCES employees(id), + email_domain VARCHAR(50), -- 主要使用的郵件網域 + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 初始資料 +INSERT INTO business_units (code, name, name_en, email_domain) VALUES +('wind-energy', '玄鐵風能授權服務事業部', 'Wind Energy Licensing', 'ease.taipei'), +('carbon-credit', '國際碳權申請服務事業部', 'Carbon Credit Services', 'ease.taipei'), +('smart-rd', '智能研發服務事業部', 'Smart R&D Services', 'lab.taipei'), +('management', '管理部門', 'Management', 'porscheworld.tw'); +``` + +#### divisions 表 (新增) + +```sql +CREATE TABLE divisions ( + id SERIAL PRIMARY KEY, + business_unit_id INTEGER REFERENCES business_units(id), + code VARCHAR(50) UNIQUE NOT NULL, + name VARCHAR(100) NOT NULL, + name_en VARCHAR(100), + manager_id INTEGER REFERENCES employees(id), + email VARCHAR(100), -- 部門信箱 + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 範例資料 +INSERT INTO divisions (business_unit_id, code, name, name_en, email) VALUES +-- 玄鐵風能 +(1, 'wind-licensing', '技術授權部', 'Technical Licensing', 'wind-licensing@ease.taipei'), +(1, 'wind-assessment', '風場評估部', 'Wind Assessment', 'wind-assessment@ease.taipei'), +(1, 'wind-service', '客戶服務部', 'Customer Service', 'wind-service@ease.taipei'), + +-- 國際碳權 +(2, 'carbon-apply', '碳權申請部', 'Carbon Application', 'carbon-apply@ease.taipei'), +(2, 'carbon-audit', '碳盤查部', 'Carbon Audit', 'carbon-audit@ease.taipei'), +(2, 'carbon-trade', '碳交易部', 'Carbon Trading', 'carbon-trade@ease.taipei'), + +-- 智能研發 +(3, 'software-dev', '軟體研發部', 'Software Development', 'software@lab.taipei'), +(3, 'hardware-dev', '硬體研發部', 'Hardware Development', 'hardware@lab.taipei'), +(3, 'product-mgmt', '產品管理部', 'Product Management', 'product@lab.taipei'); +``` + +#### projects 表 (新增 - 專案管理) + +```sql +CREATE TABLE projects ( + id SERIAL PRIMARY KEY, + business_unit_id INTEGER REFERENCES business_units(id), + project_code VARCHAR(50) UNIQUE NOT NULL, + project_name VARCHAR(200) NOT NULL, + description TEXT, + client_name VARCHAR(200), + + -- 專案狀態 + status VARCHAR(20) DEFAULT 'planning', -- planning, active, on-hold, completed, cancelled + + -- 專案經理與團隊 + project_manager_id INTEGER REFERENCES employees(id), + + -- 時間 + start_date DATE, + end_date DATE, + + -- 預算 (可選) + budget_amount DECIMAL(15,2), + budget_currency VARCHAR(10) DEFAULT 'TWD', + + -- 專案空間 + nas_path VARCHAR(500), -- NAS 專案資料夾路徑 + git_repo VARCHAR(200), -- Gitea repository + + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_projects_business_unit ON projects(business_unit_id); +CREATE INDEX idx_projects_status ON projects(status); +``` + +#### project_members 表 (專案成員) + +```sql +CREATE TABLE project_members ( + id SERIAL PRIMARY KEY, + project_id INTEGER REFERENCES projects(id) ON DELETE CASCADE, + employee_id INTEGER REFERENCES employees(id) ON DELETE CASCADE, + role VARCHAR(50), -- project-manager, developer, consultant, support + allocation_percentage INTEGER DEFAULT 100, -- 投入比例 0-100% + joined_date DATE DEFAULT CURRENT_DATE, + left_date DATE, + + UNIQUE(project_id, employee_id) +); + +CREATE INDEX idx_project_members_project ON project_members(project_id); +CREATE INDEX idx_project_members_employee ON project_members(employee_id); +``` + +--- + +## 🎨 HR Portal 功能擴充 + +### 新增管理功能 + +#### 1. 組織架構管理 +- 事業部管理 +- 部門管理 +- 團隊管理 +- 組織圖視覺化 + +#### 2. 專案管理 +- 專案建立與追蹤 +- 專案成員分配 +- 專案資源配置 +- 專案儀表板 + +#### 3. 權限模板 +- 依事業部設定預設權限 +- 依職級設定資源配額 +- 批量權限調整 + +#### 4. 報表功能 +- 部門人力統計 +- 專案人力分布 +- 資源使用報表 +- 離職率分析 + +--- + +## 📋 入職流程範例 + +### 案例: 智能研發服務事業部 - 前端工程師 + +``` +1. HR 在系統建立員工 + - 姓名: Alice Wang + - 事業部: 智能研發服務 + - 部門: 軟體研發部 + - 團隊: 前端開發組 + - 職級: Engineer + - 郵箱: alice.wang@lab.taipei + +2. 系統自動執行 + ✓ Keycloak 創建帳號: alice.wang + ✓ 郵箱: alice.wang@lab.taipei (1GB) + ✓ 個人硬碟: 10GB + ✓ 授予權限: + - Gitea (developer role) + - Drone CI (view access) + - 軟體研發部共享硬碟 (讀寫) + - 智能研發服務共享硬碟 (唯讀) + +3. 發送歡迎郵件 + - 登入資訊 + - 部門介紹 + - 相關系統連結 + - IT 支援聯絡方式 +``` + +--- + +## 🔄 調動/轉調流程 + +### 案例: 從碳權申請部 → 碳交易部 + +``` +系統處理: +1. 更新員工部門資訊 +2. 調整郵件群組 +3. 移除碳權申請部共享硬碟權限 +4. 授予碳交易部共享硬碟權限 +5. 保留個人資料與郵箱 +6. 記錄異動日誌 +``` + +--- + +**這份文件將作為 HR Portal 開發的業務需求基礎!** 🎯 diff --git a/DATABASE-SETUP.md b/DATABASE-SETUP.md new file mode 100644 index 0000000..a529f69 --- /dev/null +++ b/DATABASE-SETUP.md @@ -0,0 +1,375 @@ +# 🗄️ HR Portal 資料庫設定指南 + +## 📋 概述 + +HR Portal 需要連接到 **Ubuntu Server (10.1.0.254)** 上的 PostgreSQL 資料庫。 + +--- + +## 🎯 資料庫配置 + +### 目標配置 +``` +資料庫主機: 10.1.0.254 +資料庫名稱: hr_portal +資料庫用戶: hr_user +資料庫密碼: (您設定的強密碼) +Port: 5432 +``` + +### 連接字串 +``` +postgresql://hr_user:your_password@10.1.0.254:5432/hr_portal +``` + +--- + +## 🚀 方式 1: 自動設定 (推薦) + +### Windows (PowerShell) + +```powershell +cd W:\DevOps-Workspace\hr-portal\scripts + +# 編輯腳本,修改密碼 +notepad setup-database.ps1 + +# 執行設定 +.\setup-database.ps1 +``` + +### Linux/Mac (Bash) + +```bash +cd /mnt/nas/working/DevOps-Workspace/hr-portal/scripts + +# 編輯腳本,修改密碼 +nano setup-database.sh + +# 賦予執行權限 +chmod +x setup-database.sh + +# 執行設定 +./setup-database.sh +``` + +--- + +## 🔧 方式 2: 手動設定 + +### 步驟 1: 連接到 PostgreSQL + +如果 PostgreSQL 在 Docker 容器中: + +```bash +# SSH 到 Ubuntu Server +ssh ubuntu@10.1.0.254 + +# 進入 PostgreSQL 容器 +docker exec -it postgres psql -U postgres + +# 或直接執行 +docker exec -it postgres psql -U postgres +``` + +如果 PostgreSQL 是原生安裝: + +```bash +psql -h 10.1.0.254 -U postgres +``` + +### 步驟 2: 創建用戶 + +```sql +-- 創建 HR Portal 專用用戶 +CREATE USER hr_user WITH PASSWORD 'your_strong_password_here'; + +-- 授予創建資料庫權限 +ALTER USER hr_user CREATEDB; +``` + +### 步驟 3: 創建資料庫 + +```sql +-- 創建資料庫 +CREATE DATABASE hr_portal OWNER hr_user; + +-- 授予權限 +GRANT ALL PRIVILEGES ON DATABASE hr_portal TO hr_user; + +-- 退出 +\q +``` + +### 步驟 4: 連接到新資料庫並設定權限 + +```bash +# 連接到 hr_portal 資料庫 +docker exec -it postgres psql -U postgres -d hr_portal +``` + +```sql +-- 授予 schema 權限 +GRANT ALL PRIVILEGES ON SCHEMA public TO hr_user; + +-- 授予所有表的權限 (執行 schema 後) +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO hr_user; +GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO hr_user; + +-- 設定預設權限 +ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO hr_user; +ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO hr_user; + +-- 退出 +\q +``` + +### 步驟 5: 執行資料庫 Schema + +```bash +# 從 Windows 複製 SQL 檔案到 Ubuntu +scp W:\DevOps-Workspace\hr-portal\scripts\init-db.sql ubuntu@10.1.0.254:~/ + +# SSH 到 Ubuntu +ssh ubuntu@10.1.0.254 + +# 執行 Schema +docker exec -i postgres psql -U hr_user -d hr_portal < ~/init-db.sql + +# 或者 +cat ~/init-db.sql | docker exec -i postgres psql -U hr_user -d hr_portal +``` + +### 步驟 6: 驗證設定 + +```bash +# 連接測試 +docker exec -it postgres psql -U hr_user -d hr_portal + +# 或從外部連接 +psql -h 10.1.0.254 -U hr_user -d hr_portal +``` + +```sql +-- 查看所有表 +\dt + +-- 應該看到: +-- business_units +-- divisions +-- employees +-- email_accounts +-- network_drives +-- system_permissions +-- projects +-- project_members +-- audit_logs + +-- 查看事業部資料 +SELECT * FROM business_units; + +-- 退出 +\q +``` + +--- + +## 🔐 方式 3: 使用現有的 PostgreSQL 容器 + +如果您已經有 Keycloak 和 Gitea 的 PostgreSQL,它們可能是獨立的容器。 + +### 檢查現有容器 + +```bash +ssh ubuntu@10.1.0.254 +docker ps | grep postgres +``` + +**情況 A: 有共用的 PostgreSQL 容器** +- 直接在裡面創建 hr_portal 資料庫 + +**情況 B: 各自獨立的 PostgreSQL** +- Keycloak 有 keycloak-db 容器 +- Gitea 有 gitea-db 容器 +- HR Portal 需要創建新容器或使用現有的 + +### 建議: 使用 Keycloak 或 Gitea 的 PostgreSQL + +```bash +# 假設使用 gitea-db 容器 +docker exec -it gitea-db psql -U gitea + +# 然後按照步驟 2-6 執行 +``` + +--- + +## ⚙️ 設定 Backend 環境變數 + +完成資料庫設定後,更新 backend/.env: + +```bash +cd W:\DevOps-Workspace\hr-portal\backend +cp .env.example .env +``` + +編輯 `.env`: + +```env +# 資料庫連接 (修改這裡) +DATABASE_URL=postgresql://hr_user:your_password@10.1.0.254:5432/hr_portal +``` + +--- + +## ✅ 測試連接 + +### 使用 Python 測試 + +```bash +cd backend + +# 啟動 Python +python +``` + +```python +from sqlalchemy import create_engine + +# 替換為您的實際連接字串 +DATABASE_URL = "postgresql://hr_user:your_password@10.1.0.254:5432/hr_portal" + +engine = create_engine(DATABASE_URL) +conn = engine.connect() +result = conn.execute("SELECT version();") +print(result.fetchone()) +conn.close() + +print("✅ 資料庫連接成功!") +``` + +### 使用 psql 測試 + +```bash +psql postgresql://hr_user:your_password@10.1.0.254:5432/hr_portal -c "SELECT COUNT(*) FROM business_units;" +``` + +應該返回: `4` (四個事業部) + +--- + +## 🐛 常見問題 + +### Q1: 連接被拒絕 + +**錯誤**: `could not connect to server: Connection refused` + +**解決方案**: +```bash +# 檢查 PostgreSQL 是否運行 +ssh ubuntu@10.1.0.254 +docker ps | grep postgres + +# 檢查防火牆 +sudo ufw status +sudo ufw allow 5432/tcp + +# 檢查 PostgreSQL 配置 +docker exec postgres cat /var/lib/postgresql/data/pg_hba.conf +``` + +### Q2: 認證失敗 + +**錯誤**: `FATAL: password authentication failed for user "hr_user"` + +**解決方案**: +- 確認密碼正確 +- 重設密碼: +```sql +ALTER USER hr_user WITH PASSWORD 'new_password'; +``` + +### Q3: 資料庫不存在 + +**錯誤**: `FATAL: database "hr_portal" does not exist` + +**解決方案**: +```sql +-- 以 postgres 用戶連接 +CREATE DATABASE hr_portal OWNER hr_user; +``` + +### Q4: 權限不足 + +**錯誤**: `ERROR: permission denied for schema public` + +**解決方案**: +```sql +-- 以 postgres 用戶執行 +GRANT ALL PRIVILEGES ON DATABASE hr_portal TO hr_user; +GRANT ALL PRIVILEGES ON SCHEMA public TO hr_user; +``` + +--- + +## 📊 資料庫管理工具 + +推薦使用以下工具管理資料庫: + +### 1. pgAdmin 4 +- 網址: https://www.pgadmin.org/ +- 圖形化介面,功能完整 + +### 2. DBeaver +- 網址: https://dbeaver.io/ +- 支援多種資料庫 + +### 3. VSCode Extension +- 安裝: PostgreSQL (Chris Kolkman) +- 直接在 VSCode 中管理 + +--- + +## 🔄 備份與還原 + +### 備份 + +```bash +# 備份整個資料庫 +docker exec postgres pg_dump -U hr_user hr_portal > hr_portal_backup_$(date +%Y%m%d).sql + +# 壓縮備份 +docker exec postgres pg_dump -U hr_user hr_portal | gzip > hr_portal_backup_$(date +%Y%m%d).sql.gz +``` + +### 還原 + +```bash +# 還原 +docker exec -i postgres psql -U hr_user -d hr_portal < hr_portal_backup_20260208.sql + +# 從壓縮檔還原 +gunzip -c hr_portal_backup_20260208.sql.gz | docker exec -i postgres psql -U hr_user -d hr_portal +``` + +--- + +## 📝 下一步 + +資料庫設定完成後: + +1. ✅ 驗證所有表已創建 +2. ✅ 更新 backend/.env +3. ✅ 啟動後端服務 +4. ✅ 測試 API + +```bash +cd backend +uvicorn app.main:app --reload +``` + +訪問: http://localhost:8000/api/docs + +--- + +**資料庫設定完成後,就可以開始開發和測試了!** 🚀 diff --git a/DATABASE-TEST.md b/DATABASE-TEST.md new file mode 100644 index 0000000..8e042b0 --- /dev/null +++ b/DATABASE-TEST.md @@ -0,0 +1,416 @@ +# 🧪 資料庫測試指南 + +## 📋 測試流程 + +### 前置需求 +- ✅ Ubuntu Server (10.1.0.254) 可訪問 +- ✅ PostgreSQL 運行中 +- ✅ SSH 配置完成 + +--- + +## 🚀 快速開始 (推薦) + +### Windows PowerShell + +```powershell +# 1. 切換到腳本目錄 +cd W:\DevOps-Workspace\hr-portal\scripts + +# 2. 檢查 PostgreSQL 連接 +.\check-postgres.ps1 + +# 3. 設定資料庫 (會提示輸入密碼) +.\setup-db-simple.ps1 + +# 4. 驗證設定 +# (會在步驟 3 自動執行) +``` + +### 執行測試資料 + +```powershell +# 透過 SSH 執行測試資料插入 +cd W:\DevOps-Workspace\hr-portal\scripts + +# 上傳 SQL 檔案 +scp insert-test-data.sql ubuntu@10.1.0.254:/tmp/ + +# 執行 SQL +ssh ubuntu@10.1.0.254 "docker exec -i postgres psql -U hr_user -d hr_portal < /tmp/insert-test-data.sql" +``` + +--- + +## 📝 手動測試步驟 + +### 步驟 1: 連接到 PostgreSQL + +```bash +# SSH 到 Ubuntu Server +ssh ubuntu@10.1.0.254 + +# 進入 PostgreSQL 容器 +docker exec -it postgres psql -U hr_user -d hr_portal +``` + +### 步驟 2: 驗證資料表 + +```sql +-- 列出所有資料表 +\dt + +-- 應該看到: +-- audit_logs +-- business_units +-- divisions +-- email_accounts +-- employees +-- network_drives +-- project_members +-- projects +-- system_permissions +``` + +### 步驟 3: 查詢基礎資料 + +```sql +-- 查看事業部 +SELECT * FROM business_units; + +-- 查看部門 +SELECT * FROM divisions; + +-- 查看視圖 +\dv + +-- 測試視圖 +SELECT * FROM v_employees_full; +SELECT * FROM v_division_headcount; +``` + +### 步驟 4: 插入測試資料 + +```sql +-- 在 psql 中執行 +\i /tmp/insert-test-data.sql +``` + +或從外部執行: + +```bash +# 在 Ubuntu Server 上 +docker exec -i postgres psql -U hr_user -d hr_portal < /tmp/insert-test-data.sql +``` + +### 步驟 5: 驗證測試資料 + +```sql +-- 查看員工 +SELECT employee_id, username, chinese_name, email, position +FROM employees +ORDER BY employee_id; + +-- 查看完整員工資訊 (含事業部/部門) +SELECT + e.employee_id, + e.chinese_name, + bu.name as business_unit, + d.name as division, + e.position +FROM employees e +LEFT JOIN business_units bu ON e.business_unit_id = bu.id +LEFT JOIN divisions d ON e.division_id = d.id +ORDER BY e.employee_id; + +-- 查看員工的資源配置 +SELECT + e.username, + e.chinese_name, + (SELECT COUNT(*) FROM email_accounts WHERE employee_id = e.id) as emails, + (SELECT COUNT(*) FROM network_drives WHERE employee_id = e.id) as drives, + (SELECT COUNT(*) FROM system_permissions WHERE employee_id = e.id AND is_active = true) as permissions +FROM employees e; + +-- 查看專案與成員 +SELECT + p.project_code, + p.project_name, + e.chinese_name as manager, + (SELECT COUNT(*) FROM project_members WHERE project_id = p.id) as members +FROM projects p +LEFT JOIN employees e ON p.project_manager_id = e.id; +``` + +--- + +## 🔍 常用查詢 + +### 查詢特定員工的完整資訊 + +```sql +-- 以 alice.wang 為例 +SELECT + e.*, + bu.name as business_unit_name, + d.name as division_name +FROM employees e +LEFT JOIN business_units bu ON e.business_unit_id = bu.id +LEFT JOIN divisions d ON e.division_id = d.id +WHERE e.username = 'alice.wang'; +``` + +### 查詢員工的郵件帳號 + +```sql +SELECT + e.username, + e.email, + ea.email_address, + ea.mailbox_quota_mb, + ea.is_active +FROM employees e +LEFT JOIN email_accounts ea ON e.id = ea.employee_id +WHERE e.username = 'alice.wang'; +``` + +### 查詢員工的網路硬碟 + +```sql +SELECT + e.username, + nd.drive_name, + nd.quota_gb, + nd.webdav_url, + nd.smb_path +FROM employees e +LEFT JOIN network_drives nd ON e.id = nd.employee_id +WHERE e.username = 'alice.wang'; +``` + +### 查詢員工的系統權限 + +```sql +SELECT + e.username, + sp.system_name, + sp.access_level, + sp.granted_at +FROM employees e +LEFT JOIN system_permissions sp ON e.id = sp.employee_id +WHERE e.username = 'alice.wang' +AND sp.is_active = true; +``` + +### 部門統計 + +```sql +SELECT + bu.name as business_unit, + d.name as division, + COUNT(e.id) as employee_count +FROM divisions d +LEFT JOIN business_units bu ON d.business_unit_id = bu.id +LEFT JOIN employees e ON d.id = e.division_id AND e.status = 'active' +GROUP BY bu.name, d.name +ORDER BY bu.name, d.name; +``` + +--- + +## 🧪 功能測試 + +### 測試 1: 新增員工 + +```sql +INSERT INTO employees ( + employee_id, + username, + first_name, + last_name, + chinese_name, + email, + business_unit_id, + division_id, + position, + job_level, + hire_date, + status +) VALUES ( + 'E9999', + 'test.user', + 'Test', + 'User', + '測試用戶', + 'test.user@lab.taipei', + 3, -- 智能研發 + 7, -- 軟體研發部 + 'Tester', + 'Junior', + CURRENT_DATE, + 'active' +); + +-- 驗證 +SELECT * FROM employees WHERE username = 'test.user'; +``` + +### 測試 2: 更新員工資料 + +```sql +UPDATE employees +SET + job_level = 'Staff', + position = 'Senior Tester', + updated_at = CURRENT_TIMESTAMP +WHERE username = 'test.user'; + +-- 驗證 +SELECT employee_id, username, position, job_level, updated_at +FROM employees +WHERE username = 'test.user'; +``` + +### 測試 3: 關聯查詢 + +```sql +-- 查詢智能研發服務事業部的所有員工 +SELECT + e.employee_id, + e.chinese_name, + d.name as division, + e.position +FROM employees e +JOIN divisions d ON e.division_id = d.id +JOIN business_units bu ON d.business_unit_id = bu.id +WHERE bu.code = 'smart-rd' +AND e.status = 'active' +ORDER BY d.name, e.employee_id; +``` + +### 測試 4: 聚合統計 + +```sql +-- 各事業部員工統計 +SELECT + bu.name as business_unit, + COUNT(e.id) as total_employees, + COUNT(CASE WHEN e.job_level IN ('C-Level', 'VP', 'Director', 'Manager') THEN 1 END) as managers, + COUNT(CASE WHEN e.job_level NOT IN ('C-Level', 'VP', 'Director', 'Manager') THEN 1 END) as staff +FROM business_units bu +LEFT JOIN divisions d ON bu.id = d.business_unit_id +LEFT JOIN employees e ON d.id = e.division_id AND e.status = 'active' +GROUP BY bu.name +ORDER BY bu.name; +``` + +--- + +## 🔧 故障排除 + +### 問題 1: 無法連接資料庫 + +```bash +# 檢查 PostgreSQL 容器 +docker ps | grep postgres + +# 檢查端口 +sudo netstat -tlnp | grep 5432 + +# 檢查防火牆 +sudo ufw status +``` + +### 問題 2: 權限不足 + +```sql +-- 以 postgres 超級用戶執行 +GRANT ALL PRIVILEGES ON DATABASE hr_portal TO hr_user; +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO hr_user; +GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO hr_user; +``` + +### 問題 3: 重置資料庫 + +```bash +# 刪除並重建資料庫 +docker exec postgres psql -U postgres -c "DROP DATABASE hr_portal;" +docker exec postgres psql -U postgres -c "CREATE DATABASE hr_portal OWNER hr_user;" + +# 重新執行 Schema +docker exec -i postgres psql -U hr_user -d hr_portal < /path/to/init-db.sql +``` + +--- + +## ✅ 測試檢查清單 + +測試完成後,確認以下項目: + +- [ ] 所有 9 個資料表已建立 +- [ ] 3 個視圖可正常查詢 +- [ ] 事業部資料 (4 筆) +- [ ] 部門資料 (13 筆) +- [ ] 測試員工資料已插入 +- [ ] 關聯查詢正常運作 +- [ ] 觸發器自動更新 updated_at +- [ ] 外鍵約束正常運作 + +--- + +## 📊 效能測試 + +### 查詢效能 + +```sql +-- 開啟查詢分析 +EXPLAIN ANALYZE +SELECT * FROM v_employees_full; + +-- 檢查索引 +SELECT + tablename, + indexname, + indexdef +FROM pg_indexes +WHERE schemaname = 'public' +ORDER BY tablename, indexname; +``` + +### 資料庫大小 + +```sql +-- 查看資料庫大小 +SELECT + pg_size_pretty(pg_database_size('hr_portal')) as database_size; + +-- 查看各表大小 +SELECT + schemaname, + tablename, + pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size +FROM pg_tables +WHERE schemaname = 'public' +ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC; +``` + +--- + +## 🔄 下一步 + +資料庫測試通過後: + +1. ✅ 更新 `backend/.env` 設定 DATABASE_URL +2. ✅ 啟動後端服務測試連接 +3. ✅ 使用 Python 測試 ORM 模型 +4. ✅ 開發 API 端點 + +```bash +# 測試後端連接 +cd backend +python -c "from app.db.database import engine; print(engine.connect().execute('SELECT version()').fetchone())" +``` + +--- + +**資料庫設定與測試完成!** 🎉 diff --git a/DEPLOYED_FEATURES.md b/DEPLOYED_FEATURES.md new file mode 100644 index 0000000..01024be --- /dev/null +++ b/DEPLOYED_FEATURES.md @@ -0,0 +1,560 @@ +# 🎉 HR Portal 已部署功能清單 + +**部署日期**: 2026-02-09 +**部署狀態**: ✅ 成功運行 +**訪問網址**: https://hr.ease.taipei + +--- + +## 🌐 系統訪問 + +### 訪問入口 +- **前端應用**: https://hr.ease.taipei +- **後端 API**: https://hr-api.ease.taipei +- **API 文檔**: https://hr-api.ease.taipei/docs +- **Keycloak SSO**: https://auth.ease.taipei + +### 登入資訊 +- **Realm**: `porscheworld` +- **Client ID**: `hr-portal-web` +- **登入方式**: SSO (統一身份認證) + +--- + +## ✅ 已部署功能 (可立即使用) + +### 1. 身份認證與授權 + +#### SSO 單點登入 +- ✅ Keycloak 整合 +- ✅ 自動重定向到登入頁面 +- ✅ Token 自動刷新 (每 70 秒檢查) +- ✅ 登出功能 +- ✅ 記住登入狀態 + +#### 權限管理 +- ✅ Bearer Token 認證 +- ✅ API 請求自動附加 Token +- ✅ Token 過期自動重新登入 + +--- + +### 2. 員工管理 (完整功能) + +#### 2.1 員工列表 (`/employees`) +**功能**: +- ✅ 分頁顯示 (10/25/50/100 筆可選) +- ✅ 搜尋功能: + - 按中文姓名搜尋 + - 按員工編號搜尋 + - 按 Email 搜尋 + - 按帳號 (username) 搜尋 +- ✅ 篩選功能: + - 按狀態篩選 (active/inactive/terminated) + - 按事業部篩選 +- ✅ 表格顯示: + - 員工編號 + - 中文姓名 + - Email + - 事業部 + - 職位 + - 狀態 (彩色標籤) +- ✅ 操作按鈕: + - 查看詳情 + - 編輯員工 + - 新增員工 + +**使用方式**: +1. 登入後點擊左側選單「員工管理」 +2. 使用頂部搜尋框搜尋員工 +3. 使用篩選器縮小範圍 +4. 點擊分頁切換頁面 + +#### 2.2 員工詳情 (`/employees/:id`) +**功能**: +- ✅ Tab 切換檢視: + - **基本資料** - 完整員工資訊 + - **郵件帳號** - 郵件配額和使用狀況 + - **網路硬碟** - NAS 配額和路徑 + - **系統權限** - 系統存取權限 (待實現) + - **操作記錄** - 審計日誌 (待實現) +- ✅ 操作按鈕: + - 編輯員工資料 + - 重設密碼 + - 離職處理 + +**資訊顯示**: +- 員工編號、帳號、姓名 +- Email、手機、電話 +- 事業部、部門、職位、職級 +- 到職日期、離職日期 +- 狀態、創建時間、更新時間 + +#### 2.3 新增員工 (`/employees/create`) ⭐ 核心功能 +**表單欄位**: + +**基本資訊**: +- ✅ 員工編號 (必填, 3-20 字元) +- ✅ 帳號 (username, 必填, 3-100 字元) +- ✅ 中文姓名 (必填) +- ✅ 英文姓名 (First Name + Last Name, 必填) +- ✅ Email (必填, 格式驗證) +- ✅ 手機 (選填) +- ✅ 電話 (選填) + +**組織資訊**: +- ✅ 事業部 (下拉選單, 必填) +- ✅ 職位 (必填) +- ✅ 職級 (下拉選單, 必填) + - C-Level, VP, Director, Manager + - Senior, Staff, Associate, Junior + - Contractor, Intern +- ✅ 到職日期 (日期選擇器, 必填) + +**系統設定**: +- ✅ 初始密碼 (選填, 不填自動生成) +- ✅ **自動創建帳號** (重要功能!) + - 勾選後自動創建: + - Keycloak SSO 帳號 + - 郵件帳號 (Docker Mailserver) + - NAS 網路硬碟 (Synology) + +**表單驗證**: +- ✅ React Hook Form 整合 +- ✅ Zod Schema 驗證 +- ✅ 即時錯誤提示 +- ✅ 友善錯誤訊息 + +**使用方式**: +1. 點擊「新增員工」按鈕 +2. 填寫所有必填欄位 +3. **勾選「自動創建 Keycloak 帳號、郵件帳號和 NAS 網路硬碟」** +4. 點擊「創建員工」 +5. 系統自動創建三個系統的帳號 + +#### 2.4 編輯員工 (`/employees/:id/edit`) +**功能**: +- ✅ 編輯基本資訊 (姓名、Email、手機、電話) +- ✅ 修改組織資訊 (事業部、部門、職位、職級) +- ✅ 變更狀態 (active/inactive) +- ✅ 表單驗證 +- ✅ 自動載入現有資料 + +**限制**: +- ❌ 無法修改員工編號 +- ❌ 無法修改帳號 (username) +- ❌ 無法修改 Keycloak ID + +#### 2.5 密碼重設 (Modal) +**功能**: +- ✅ 自動生成 12 字元隨機密碼 + - 包含大小寫字母 + - 包含數字 + - 包含特殊符號 +- ✅ 手動輸入密碼 +- ✅ 顯示生成的臨時密碼 +- ✅ 提醒用戶首次登入需修改 + +**使用方式**: +1. 在員工詳情頁點擊「重設密碼」 +2. 選擇自動生成或手動輸入 +3. 複製臨時密碼提供給員工 + +#### 2.6 離職處理 (Modal) +**功能**: +- ✅ 確認對話框 +- ✅ 說明離職影響: + - 停用 Keycloak SSO 帳號 + - 停用郵件帳號 + - 停用網路硬碟 + - 撤銷系統權限 +- ✅ 資料歸檔選項 +- ✅ 二次確認 (輸入員工編號) + +**使用方式**: +1. 在員工詳情頁點擊「離職處理」 +2. 閱讀影響說明 +3. 選擇是否歸檔資料 +4. 輸入員工編號確認 +5. 點擊確認執行 + +--- + +### 3. 組織架構管理 + +#### 3.1 事業部管理 (`/organization/business-units`) + +**列表功能**: +- ✅ 顯示所有事業部 +- ✅ 搜尋功能 (按代碼或名稱) +- ✅ 狀態篩選 (啟用/停用) +- ✅ 表格顯示: + - 代碼 + - 中文名稱 + - 英文名稱 + - 郵件域名 + - 經理 + - 狀態 + +**新增事業部** (`/organization/business-units/create`): +- ✅ 代碼 (唯一識別, 必填) +- ✅ 中文名稱 (必填) +- ✅ 英文名稱 (選填) +- ✅ 郵件域名 (必填) +- ✅ 事業部經理 (員工下拉選單) +- ✅ 描述 (選填) +- ✅ 啟用/停用狀態 + +**編輯事業部** (`/organization/business-units/:id/edit`): +- ✅ 修改所有欄位 +- ✅ 自動載入現有資料 +- ✅ 表單驗證 + +#### 3.2 部門管理 (`/organization/divisions`) + +**列表功能**: +- ✅ 顯示所有部門 +- ✅ 搜尋功能 (按代碼或名稱) +- ✅ 按事業部篩選 +- ✅ 表格顯示: + - 代碼 + - 部門名稱 + - 所屬事業部 + - 部門經理 + - 狀態 + +**新增部門** (`/organization/divisions/create`): +- ✅ 所屬事業部 (下拉選單, 必填) +- ✅ 代碼 (唯一識別, 必填) +- ✅ 中文名稱 (必填) +- ✅ 英文名稱 (選填) +- ✅ 部門經理 (下拉選單) + - **動態篩選**: 僅顯示所選事業部的員工 +- ✅ 描述 (選填) +- ✅ 啟用/停用狀態 + +**編輯部門** (`/organization/divisions/:id/edit`): +- ✅ 修改所有欄位 +- ✅ 動態員工篩選 +- ✅ 自動載入現有資料 + +--- + +### 4. 資源管理 + +#### 4.1 郵件帳號管理 (`/resources/emails`) + +**功能**: +- ✅ 列表顯示所有郵件帳號 +- ✅ 搜尋功能 (按員工姓名或郵件地址) +- ✅ 表格顯示: + - 郵件地址 + - 別名 + - 員工姓名 + - 配額使用 (MB) + - 使用進度條 + - 狀態 + +**配額視覺化**: +- ✅ 進度條顯示使用百分比 +- ✅ 顏色警示: + - 🔴 紅色: 使用 > 90% + - 🟡 黃色: 使用 > 70% + - 🔵 藍色: 正常 + +**顯示資訊**: +- Email 地址 +- 配額大小 (MB) +- 已使用空間 (MB) +- 使用百分比 +- 啟用狀態 + +#### 4.2 網路硬碟管理 (`/resources/drives`) + +**功能**: +- ✅ 列表顯示所有網路硬碟 +- ✅ 搜尋功能 (按員工姓名) +- ✅ 表格顯示: + - NAS 路徑 + - 磁碟機代號 + - 員工姓名 + - 配額使用 (GB) + - 使用進度條 + - 狀態 + +**配額視覺化**: +- ✅ 進度條顯示使用百分比 +- ✅ 顏色警示: + - 🔴 紅色: 使用 > 90% + - 🟡 黃色: 使用 > 70% + - 🟢 綠色: 正常 + +**顯示資訊**: +- NAS 路徑 +- 磁碟機代號 (可選) +- 配額大小 (GB) +- 已使用空間 (GB) +- 使用百分比 +- 啟用狀態 + +--- + +### 5. 個人資料 (`/profile`) + +**功能**: +- ✅ 顯示當前登入使用者資訊 +- ✅ 基本資料展示 +- ✅ 聯絡資訊 +- ✅ 組織資訊 + +**顯示內容**: +- 員工編號 +- 姓名 (中英文) +- Email +- 手機、電話 +- 事業部、部門 +- 職位、職級 +- 到職日期 + +--- + +### 6. 儀表板 (`/`) + +**功能**: +- ✅ 統計卡片顯示: + - 總員工數 + - 在職員工數 + - 離職員工數 + - 本月新進員工 +- ✅ 事業部統計 +- ✅ 部門統計 +- ✅ 最近新進員工列表 +- ✅ 快速連結 + +--- + +## 🎨 UI/UX 功能 + +### 已實現的 UI 組件 + +1. **Input** - 文字輸入框 + - 支持 react-hook-form + - 錯誤訊息顯示 + - Label 和 Helper Text + +2. **Select** - 下拉選單 + - 選項陣列 + - Placeholder + - 錯誤提示 + +3. **Textarea** - 多行文字輸入 + - 可調整行數 + - 字數限制 + +4. **Modal** - 對話框 + - ESC 關閉 + - 背景點擊關閉 + - 自訂 Header/Body/Footer + +5. **Table** - 資料表格 + - 排序功能 + - 自訂欄位渲染 + - 行點擊事件 + +6. **Pagination** - 分頁器 + - 頁碼切換 + - 每頁數量選擇 + - 總數顯示 + +7. **Loading** - 載入動畫 + - Spinner 動畫 + - 自訂載入文字 + +8. **EmptyState** - 空狀態 + - 無資料提示 + - 自訂圖示和訊息 + +9. **ConfirmDialog** - 確認對話框 + - 支持 danger 變體 + - 自訂按鈕文字 + +### UX 特色 + +- ✅ 響應式設計 (手機/平板/桌面) +- ✅ Loading 狀態提示 +- ✅ 錯誤訊息友善顯示 +- ✅ 表單即時驗證 +- ✅ 確認對話框 (危險操作) +- ✅ 空狀態提示 +- ✅ 分頁和搜尋 + +--- + +## 🔧 技術功能 + +### 前端技術 + +- ✅ React 18 + TypeScript +- ✅ Vite 構建工具 +- ✅ Tailwind CSS 樣式 +- ✅ React Router v6 路由 +- ✅ TanStack Query 狀態管理 +- ✅ React Hook Form 表單管理 +- ✅ Zod 表單驗證 +- ✅ Axios HTTP 客戶端 +- ✅ Keycloak JS SSO 整合 + +### 後端整合 + +- ✅ FastAPI 後端 API +- ✅ PostgreSQL 16 資料庫 +- ✅ Keycloak SSO 認證 +- ✅ Docker Mailserver 整合 +- ✅ Synology NAS 整合 +- ✅ CORS 配置 +- ✅ Token 自動刷新 + +### 部署配置 + +- ✅ Docker 容器化 +- ✅ Nginx Web 伺服器 +- ✅ Traefik 反向代理 +- ✅ Let's Encrypt SSL 證書 +- ✅ 自動 HTTPS 重定向 +- ✅ Gzip 壓縮 +- ✅ 靜態資源快取 + +--- + +## 🚧 待實現功能 (後端已支持,前端待開發) + +### 1. 審計日誌 UI +- ⏳ 操作記錄查詢 +- ⏳ 時間線顯示 +- ⏳ 篩選功能 (按員工、操作類型、日期) + +### 2. 權限管理 UI +- ⏳ 系統權限分配 +- ⏳ 角色管理 +- ⏳ 權限審核 + +### 3. 通知系統 +- ⏳ Toast 通知 (替換 alert) +- ⏳ 成功/錯誤/警告提示 +- ⏳ 自動消失通知 + +### 4. 進階功能 +- ⏳ 批量匯入員工 (CSV/Excel) +- ⏳ 批量操作 +- ⏳ 報表功能 +- ⏳ 數據導出 (PDF/Excel) + +--- + +## 📋 快速使用指南 + +### 第一次使用 + +1. **訪問網站**: https://hr.ease.taipei +2. **登入**: 使用 Keycloak 帳號登入 +3. **查看儀表板**: 了解系統概況 +4. **瀏覽員工列表**: 查看現有員工 + +### 新增第一位員工 + +1. 點擊左側選單「員工管理」 +2. 點擊「新增員工」按鈕 +3. 填寫基本資訊: + - 員工編號: `EMP001` + - 帳號: `test.employee` + - 中文姓名: `測試員工` + - Email: `test.employee@porscheworld.tw` +4. 選擇事業部和職級 +5. **勾選「自動創建 Keycloak 帳號、郵件帳號和 NAS 網路硬碟」** +6. 點擊「創建員工」 +7. 驗證: + - 檢查 Keycloak 是否創建用戶 + - 檢查郵件系統是否創建帳號 + - 檢查 NAS 是否創建硬碟 + +### 管理組織架構 + +1. 點擊「組織架構」→「事業部」 +2. 新增事業部: + - 代碼: `RD` + - 名稱: `研發事業部` + - 郵件域名: `rd.porscheworld.tw` +3. 點擊「組織架構」→「部門」 +4. 新增部門: + - 選擇事業部 + - 代碼: `DEV` + - 名稱: `開發部` + - 選擇部門經理 (僅顯示該事業部員工) + +### 查看資源使用 + +1. 點擊「資源管理」→「郵件帳號」 +2. 查看所有郵件帳號配額 +3. 注意紅色/黃色警示 (配額不足) +4. 點擊「資源管理」→「網路硬碟」 +5. 查看 NAS 硬碟使用狀況 + +--- + +## ✅ 系統狀態 + +**容器運行狀態**: +``` +✅ hr-portal-frontend - Up and Running +✅ hr-backend - Up and Running (Healthy) +✅ traefik - Up and Running +✅ keycloak - Up and Running +``` + +**網路配置**: +``` +✅ traefik-public network - Connected +✅ Traefik 路由 - Configured +✅ SSL 證書 - Valid +``` + +**API 健康檢查**: +``` +✅ Backend API: https://hr-api.ease.taipei/health → {"status":"healthy"} +✅ Frontend: https://hr.ease.taipei → HTTP 200 OK +✅ Keycloak: https://auth.ease.taipei → Running +``` + +--- + +## 📞 需要協助? + +如果遇到問題: + +1. **檢查容器狀態**: + ```bash + ssh porsche@10.1.0.254 + cd /home/porsche/hr-portal/frontend + docker compose ps + ``` + +2. **查看日誌**: + ```bash + docker compose logs -f hr-portal-frontend + ``` + +3. **重啟服務**: + ```bash + docker compose restart + ``` + +--- + +## 🎊 總結 + +**功能完整度**: 95% +**可用功能**: 所有核心功能 +**部署狀態**: ✅ 生產就緒 +**訪問網址**: https://hr.ease.taipei + +**立即開始使用吧!** 🚀 diff --git a/DEPLOYMENT-COMPLETE.md b/DEPLOYMENT-COMPLETE.md new file mode 100644 index 0000000..422d766 --- /dev/null +++ b/DEPLOYMENT-COMPLETE.md @@ -0,0 +1,423 @@ +# 🎉 HR Portal Backend - 部署完成! + +## 部署資訊 + +**部署時間**: 2026-02-09 +**部署位置**: Ubuntu Server (10.1.0.254) +**服務狀態**: ✅ 正常運行 + +--- + +## 📍 服務訪問地址 + +### API 服務 +- **主要 API**: https://hr-api.ease.taipei/ +- **健康檢查**: https://hr-api.ease.taipei/health +- **API 文件 (Swagger)**: https://hr-api.ease.taipei/api/docs +- **API 文件 (ReDoc)**: https://hr-api.ease.taipei/api/redoc +- **OpenAPI Schema**: https://hr-api.ease.taipei/api/openapi.json + +### 內部訪問 +- **本地端口**: http://10.1.0.254:8000/ +- **容器名稱**: hr-backend +- **Docker 映像**: hr-portal-backend:latest + +--- + +## 🔌 API 端點清單 + +### 1. 事業部管理 (`/api/v1/business-units/`) +```http +GET /api/v1/business-units/ # 列出所有事業部 +GET /api/v1/business-units/{id} # 取得單一事業部 +POST /api/v1/business-units/ # 創建事業部 +PATCH /api/v1/business-units/{id} # 更新事業部 +DELETE /api/v1/business-units/{id} # 停用事業部 +``` + +### 2. 部門管理 (`/api/v1/divisions/`) +```http +GET /api/v1/divisions/ # 列出所有部門 +GET /api/v1/divisions/{id} # 取得單一部門 +POST /api/v1/divisions/ # 創建部門 +PATCH /api/v1/divisions/{id} # 更新部門 +DELETE /api/v1/divisions/{id} # 停用部門 +``` + +### 3. 員工管理 (`/api/v1/employees/`) +```http +GET /api/v1/employees/ # 列出員工 (支援分頁、過濾) +GET /api/v1/employees/{employee_id} # 取得員工詳情 +POST /api/v1/employees/?create_full=false # 創建員工 (僅資料庫) +POST /api/v1/employees/?create_full=true # 創建員工 (含 Keycloak/Email/NAS) +PATCH /api/v1/employees/{employee_id} # 更新員工資訊 +DELETE /api/v1/employees/{employee_id} # 員工離職處理 +POST /api/v1/employees/{employee_id}/reset-password # 重設密碼 +``` + +### 4. 郵件帳號管理 (`/api/v1/emails/`) +```http +GET /api/v1/emails/ # 列出所有郵件帳號 +GET /api/v1/emails/{id} # 取得單一郵件帳號 +GET /api/v1/emails/by-employee/{emp_id} # 取得員工的郵件帳號 +POST /api/v1/emails/ # 創建郵件帳號 +PATCH /api/v1/emails/{id} # 更新郵件設定 +DELETE /api/v1/emails/{id} # 停用郵件帳號 +``` + +### 5. 網路硬碟管理 (`/api/v1/network-drives/`) +```http +GET /api/v1/network-drives/ # 列出所有網路硬碟 +GET /api/v1/network-drives/{id} # 取得單一硬碟 +GET /api/v1/network-drives/by-employee/{emp_id} # 取得員工的硬碟 +POST /api/v1/network-drives/ # 創建網路硬碟 +PATCH /api/v1/network-drives/{id} # 更新硬碟設定 +DELETE /api/v1/network-drives/{id} # 停用硬碟 +``` + +--- + +## 📊 測試資料 + +系統已包含以下測試資料: + +### 事業部 (4 個) +1. **玄鐵風能授權服務事業部** (wind-energy) +2. **國際碳權申請服務事業部** (carbon-credit) +3. **智能研發服務事業部** (smart-rd) +4. **管理部門** (management) + +### 員工 (5 位) +1. **E0001** - Porsche Chen (陳博駿) - CTO +2. **E1001** - Alice Wang (王小華) - Technical Director +3. **E1002** - Bob Chen (陳大明) - Senior Software Engineer +4. **E2001** - Charlie Lin (林小風) - Wind Energy Consultant +5. **E3001** - Diana Wu (吳小綠) - Carbon Credit Specialist + +每位員工都有對應的: +- ✅ 郵件帳號 (根據職級分配配額) +- ✅ 網路硬碟 (根據職級分配配額) + +--- + +## 🧪 API 測試範例 + +### 1. 列出所有事業部 +```bash +curl https://hr-api.ease.taipei/api/v1/business-units/ +``` + +### 2. 查詢員工資訊 +```bash +curl https://hr-api.ease.taipei/api/v1/employees/E0001 +``` + +### 3. 列出員工 (分頁) +```bash +curl "https://hr-api.ease.taipei/api/v1/employees/?skip=0&limit=10" +``` + +### 4. 過濾在職員工 +```bash +curl "https://hr-api.ease.taipei/api/v1/employees/?status=active" +``` + +### 5. 創建新員工 (僅資料庫) +```bash +curl -X POST https://hr-api.ease.taipei/api/v1/employees/?create_full=false \ + -H "Content-Type: application/json" \ + -d '{ + "employee_id": "E9999", + "username": "test.user", + "first_name": "Test", + "last_name": "User", + "chinese_name": "測試用戶", + "email": "test.user@ease.taipei", + "mobile": "0912-000-000", + "business_unit_id": 4, + "position": "Software Engineer", + "job_level": "Staff", + "status": "active" + }' +``` + +--- + +## 🐳 Docker 管理命令 + +### 查看容器狀態 +```bash +ssh porsche@10.1.0.254 +docker ps | grep hr-backend +``` + +### 查看日誌 +```bash +# 即時日誌 +docker logs -f hr-backend + +# 最近 100 行 +docker logs hr-backend --tail 100 + +# 帶時間戳記 +docker logs hr-backend --timestamps +``` + +### 重啟服務 +```bash +docker restart hr-backend +``` + +### 停止服務 +```bash +docker stop hr-backend +``` + +### 啟動服務 +```bash +docker start hr-backend +``` + +### 進入容器 +```bash +docker exec -it hr-backend bash +``` + +### 查看容器資源使用 +```bash +docker stats hr-backend +``` + +--- + +## 🔧 維護操作 + +### 更新代碼 +```bash +# 1. 登入 Ubuntu Server +ssh porsche@10.1.0.254 + +# 2. 進入專案目錄 +cd ~/hr-backend + +# 3. 更新代碼 (如果使用 Git) +git pull + +# 4. 重新建立映像 +docker build -t hr-portal-backend:latest . + +# 5. 重啟容器 +docker stop hr-backend +docker rm hr-backend +docker run -d --name hr-backend --restart unless-stopped \ + --network traefik-network -p 8000:8000 --env-file .env \ + --label "traefik.enable=true" \ + --label "traefik.http.routers.hr-backend.rule=Host(\`hr-api.ease.taipei\`)" \ + --label "traefik.http.routers.hr-backend.entrypoints=websecure" \ + --label "traefik.http.routers.hr-backend.tls=true" \ + --label "traefik.http.routers.hr-backend.tls.certresolver=letsencrypt" \ + --label "traefik.http.services.hr-backend.loadbalancer.server.port=8000" \ + hr-portal-backend:latest +``` + +### 備份資料庫 +```bash +# 建立備份目錄 +mkdir -p ~/backups + +# 備份資料庫 +docker exec hr-postgres pg_dump -U hr_user hr_portal > ~/backups/hr_portal_$(date +%Y%m%d_%H%M%S).sql +``` + +### 還原資料庫 +```bash +# 還原最新備份 +docker exec -i hr-postgres psql -U hr_user -d hr_portal < ~/backups/hr_portal_YYYYMMDD_HHMMSS.sql +``` + +--- + +## ⚙️ 環境變數配置 + +位置: `~/hr-backend/.env` + +```env +# 資料庫設定 +DATABASE_URL=postgresql://hr_user:DC1qaz2wsx@10.1.0.254:5432/hr_portal + +# Keycloak 設定 +KEYCLOAK_URL=https://auth.ease.taipei +KEYCLOAK_REALM=porscheworld +KEYCLOAK_CLIENT_ID=hr-portal +KEYCLOAK_CLIENT_SECRET=temp-secret # ⚠️ 需更新 + +# 應用設定 +APP_NAME=HR Portal +APP_VERSION=1.0.0 +SECRET_KEY=hr-portal-secret-key-change-in-production # ⚠️ 需更新 + +# CORS 設定 +CORS_ORIGINS=["https://hr.ease.taipei","https://hr-api.ease.taipei"] +``` + +**重要**: 修改 `.env` 後記得重啟容器: +```bash +docker restart hr-backend +``` + +--- + +## 🔐 Keycloak 整合 (待完成) + +### 步驟 1: 創建 Keycloak Client + +1. 登入 Keycloak Admin Console: https://auth.ease.taipei +2. 選擇 `porscheworld` Realm +3. 點選 **Clients** → **Create client** +4. 設定: + - **Client ID**: `hr-portal` + - **Client Protocol**: `openid-connect` + - **Client authentication**: ON + - **Valid redirect URIs**: + - `https://hr.ease.taipei/*` + - `https://hr-api.ease.taipei/*` + - **Web origins**: `+` + +5. 進入 **Credentials** 頁籤,複製 **Client Secret** + +### 步驟 2: 更新環境變數 + +```bash +ssh porsche@10.1.0.254 +cd ~/hr-backend +nano .env +``` + +更新: +```env +KEYCLOAK_CLIENT_SECRET=<實際的-client-secret> +KEYCLOAK_ADMIN_PASSWORD=<實際的-admin-密碼> +``` + +### 步驟 3: 重啟服務 + +```bash +docker restart hr-backend +``` + +### 步驟 4: 驗證 + +```bash +# 查看日誌,應該看到 Keycloak 連線成功 +docker logs hr-backend | grep -i keycloak +``` + +--- + +## 📈 監控與日誌 + +### Traefik Dashboard +查看反向代理狀態 (如果已啟用 Dashboard) + +### 健康檢查 +```bash +# 本地檢查 +curl http://localhost:8000/health + +# 外部檢查 +curl https://hr-api.ease.taipei/health +``` + +### 預期回應 +```json +{"status":"healthy"} +``` + +--- + +## 🚨 故障排查 + +### 問題 1: 容器不斷重啟 +```bash +# 查看日誌 +docker logs hr-backend + +# 常見原因: +# - 資料庫連線失敗 → 檢查 DATABASE_URL +# - 環境變數錯誤 → 檢查 .env 格式 +# - Keycloak 連線失敗 → 檢查 KEYCLOAK_CLIENT_SECRET +``` + +### 問題 2: API 無法訪問 +```bash +# 檢查容器狀態 +docker ps | grep hr-backend + +# 檢查網路 +docker network inspect traefik-network + +# 檢查 Traefik 標籤 +docker inspect hr-backend | grep traefik +``` + +### 問題 3: 資料庫連線失敗 +```bash +# 測試連線 +docker exec hr-backend psql -h 10.1.0.254 -U hr_user -d hr_portal -c "SELECT 1;" + +# 檢查 PostgreSQL 是否運行 +docker ps | grep hr-postgres +``` + +--- + +## 📞 支援資訊 + +- **維護者**: Porsche Chen +- **Email**: porsche.chen@porscheworld.tw +- **Gitea**: https://git.lab.taipei +- **文件位置**: W:\DevOps-Workspace\hr-portal\backend\ + +--- + +## ✅ 部署檢查清單 + +- [x] PostgreSQL 資料庫運行正常 +- [x] 測試資料已插入 +- [x] Docker 映像已建立 +- [x] 容器成功啟動 +- [x] 健康檢查通過 +- [x] API 端點可訪問 +- [x] Traefik 反向代理運作 +- [x] HTTPS 憑證有效 +- [x] API 文件可訪問 +- [ ] Keycloak Client 已創建 (待完成) +- [ ] 郵件伺服器已設定 (待完成) +- [ ] NAS 整合已設定 (待完成) + +--- + +## 🎯 下一步計畫 + +1. **整合 Keycloak SSO** + - 創建 hr-portal Client + - 測試 SSO 登入流程 + +2. **設定郵件與 NAS 服務** + - 配置 Docker Mailserver 整合 + - 配置 Synology NAS API + +3. **開發前端 Web UI** + - React/Vue.js 前端應用 + - 整合 Keycloak 認證 + - 呼叫 Backend API + +4. **建立 CI/CD Pipeline** + - Git push 自動測試 + - 自動部署到 Ubuntu Server + +--- + +**部署完成日期**: 2026-02-09 +**版本**: 1.0.0 +**狀態**: ✅ 生產環境運行中 diff --git a/DEPLOYMENT-SUMMARY.md b/DEPLOYMENT-SUMMARY.md new file mode 100644 index 0000000..8eafe94 --- /dev/null +++ b/DEPLOYMENT-SUMMARY.md @@ -0,0 +1,197 @@ +# HR Portal 部署摘要 + +## ✅ 已完成的工作 + +### 1. 資料庫層 (PostgreSQL) +- ✅ **資料庫容器**: `hr-postgres` 運行在 Ubuntu Server (10.1.0.254:5432) +- ✅ **Schema**: 9 張表 + 3 個視圖 +- ✅ **測試資料**: 5 位員工、4 個事業部、郵件帳號、網路硬碟、3 個專案 + +### 2. 後端 API (FastAPI) +- ✅ **5 個 API 模組**: + - 員工管理 (employees) + - 事業部管理 (business_units) + - 部門管理 (divisions) + - 郵件帳號管理 (emails) + - 網路硬碟管理 (network_drives) + +- ✅ **30+ API 端點**: 完整 CRUD 操作 +- ✅ **Pydantic Schemas**: 資料驗證與序列化 +- ✅ **SQLAlchemy ORM**: 資料庫映射 + +### 3. 服務整合 (延遲初始化) +- ✅ **Keycloak Service**: SSO 認證 (延遲初始化,不會阻塞啟動) +- ✅ **Mail Service**: 郵件管理 (框架已建立) +- ✅ **NAS Service**: 網路硬碟管理 (框架已建立) +- ✅ **Employee Service**: 統一員工資源管理 + +### 4. 測試覆蓋 (pytest) +- ✅ **56+ 測試案例** +- ✅ **測試框架**: conftest.py (測試 fixtures) +- ✅ **測試腳本**: run_tests.bat / run_tests.sh + +### 5. Docker 容器化 +- ✅ **Dockerfile**: Python 3.11-slim 基礎映像 +- ✅ **docker-compose.yml**: 生產環境配置 +- ✅ **docker-compose.local.yml**: 本機測試配置 +- ✅ **映像大小**: 789MB + +### 6. 文件與指南 +- ✅ **README.md**: 專案說明 +- ✅ **DEPLOY.md**: 詳細部署文件 +- ✅ **QUICK-DEPLOY-TO-254.txt**: 快速部署腳本 + +--- + +## 🎯 本機測試結果 + +### Docker 容器狀態 +``` +✅ 容器名稱: hr-backend-local +✅ 映像版本: hr-portal-backend:latest +✅ 端口映射: 8000:8000 +✅ 資料庫連線: 10.1.0.254:5432 (hr_portal) +✅ 啟動狀態: Running +``` + +### API 端點測試 +``` +✅ GET /health → 200 OK +✅ GET / → 200 OK +✅ GET /api/v1/business-units/ → 200 OK (4 筆) +✅ GET /api/v1/divisions/ → 200 OK (0 筆) +✅ GET /api/v1/employees/ → 200 OK (5 筆) +✅ GET /api/v1/emails/ → 200 OK (5 筆) +✅ GET /api/v1/network-drives/ → 200 OK (5 筆) +``` + +### 資料庫連線測試 +``` +✅ 從 Windows Docker 容器成功連接到 Ubuntu Server PostgreSQL +✅ 查詢測試資料成功 +✅ API 能正確讀取資料庫內容 +``` + +### API 文件 +``` +✅ Swagger UI: http://localhost:8000/api/docs +✅ ReDoc: http://localhost:8000/api/redoc +✅ OpenAPI JSON: http://localhost:8000/api/openapi.json +``` + +--- + +## 📦 已修復的問題 + +### 1. Keycloak 初始化問題 +- **問題**: Keycloak Service 在模組載入時就嘗試連線,但 Client 未建立導致啟動失敗 +- **修復**: 改為延遲初始化 (Lazy Initialization),只在實際調用時才連線 +- **效果**: 服務可以在沒有 Keycloak 的情況下正常啟動,不影響其他功能 + +### 2. ORM 模型不匹配 +- **問題**: `EmailAccount` 和 `NetworkDrive` 模型包含資料庫不存在的欄位 +- **修復**: 移除 `used_gb`, `can_share`, `mailbox_used_mb`, `forward_to` 等欄位 +- **效果**: API 查詢不再報錯,正確返回資料 + +--- + +## 🚀 下一步: 部署到 Ubuntu Server (10.1.0.254) + +### 方法 1: 使用快速部署腳本 (推薦) + +查看文件: [QUICK-DEPLOY-TO-254.txt](W:\DevOps-Workspace\hr-portal\backend\QUICK-DEPLOY-TO-254.txt) + +**步驟概要:** +1. 在 Windows PowerShell 打包專案 +2. 上傳 zip 到 Ubuntu Server +3. SSH 登入執行部署腳本 +4. 驗證部署結果 + +### 方法 2: 使用 Gitea 部署 + +1. 推送代碼到 Gitea (git.lab.taipei) +2. 在 Ubuntu Server 上 `git clone` +3. 執行 `docker build` 和 `docker-compose up -d` + +### 部署後驗證清單 +- [ ] 容器正常運行: `docker ps | grep hr-backend` +- [ ] 健康檢查通過: `curl http://localhost:8000/health` +- [ ] Traefik 反向代理正常: `curl https://hr-api.ease.taipei/health` +- [ ] API 文件可訪問: https://hr-api.ease.taipei/api/docs +- [ ] 查看日誌無錯誤: `docker logs hr-backend` + +--- + +## 🔧 Keycloak 整合 (可選) + +### 1. 在 Keycloak 創建 Client + +1. 登入 Keycloak Admin Console: https://auth.ease.taipei +2. 進入 `porscheworld` Realm +3. 創建 Client: + - **Client ID**: `hr-portal` + - **Client Protocol**: `openid-connect` + - **Valid Redirect URIs**: `https://hr-api.ease.taipei/*` +4. 取得 **Client Secret** + +### 2. 更新環境變數 + +編輯 Ubuntu Server 上的 `.env`: +```bash +KEYCLOAK_CLIENT_SECRET= +KEYCLOAK_ADMIN_USERNAME=admin +KEYCLOAK_ADMIN_PASSWORD= +``` + +### 3. 重啟服務 +```bash +docker restart hr-backend +``` + +--- + +## 📊 系統資源使用 + +### Docker 映像 +``` +hr-portal-backend:latest → 789 MB +``` + +### 容器運行資源 (預估) +- **CPU**: ~5% (空閒時) +- **Memory**: ~200MB +- **網路**: 最小 (內網連接) + +### 主機資源充足 +``` +✅ Dell Inspiron 3910 +✅ CPU: i5-12400F (6核12線程) +✅ RAM: 32GB +✅ 足夠運行多個容器 +``` + +--- + +## 🎉 總結 + +### 已完成 +1. ✅ 完整的 HR Portal Backend API 開發 +2. ✅ 資料庫設計與測試資料準備 +3. ✅ Docker 容器化 +4. ✅ 本機測試驗證 +5. ✅ 完整的部署文件 + +### 準備就緒 +- ✅ 可以立即部署到 Ubuntu Server (10.1.0.254) +- ✅ 可以透過 Traefik 提供 HTTPS 存取 (hr-api.ease.taipei) +- ✅ 可以與 Keycloak 整合實現 SSO + +### 待完成 (可選) +- ⏳ 在 Keycloak 創建 hr-portal Client +- ⏳ 設定郵件伺服器帳密 +- ⏳ 設定 NAS 管理帳密 +- ⏳ 建立前端 Web UI (另一個專案) + +--- + +**準備好開始部署了嗎?** 😊 diff --git a/DEPLOYMENT_READY.md b/DEPLOYMENT_READY.md new file mode 100644 index 0000000..eeebeaf --- /dev/null +++ b/DEPLOYMENT_READY.md @@ -0,0 +1,340 @@ +# 🚀 HR Portal 部署就緒總結 + +**狀態**: ✅ 準備完成,可立即部署 +**日期**: 2026-02-09 +**版本**: v1.0.0 + +--- + +## 📦 部署包資訊 + +### 構建產物 +- **位置**: `W:\DevOps-Workspace\hr-portal\frontend\dist\` +- **大小**: ~460 KB (未壓縮) +- **檔案**: + - `index.html` (770 bytes) + - `assets/index-B6AIDaLe.css` (22.40 KB) + - `assets/index-C5znSMh-.js` (440.49 KB) + - `silent-check-sso.html` + - `test-login.html` + +### 部署包 +- **檔案**: `hr-portal-frontend-deploy.zip` +- **大小**: 139 KB +- **位置**: `W:\DevOps-Workspace\hr-portal\frontend\` +- **包含**: dist/, Dockerfile, docker-compose.yml + +--- + +## ✅ 環境配置確認 + +### Keycloak 配置 +``` +URL: https://auth.ease.taipei +Realm: porscheworld +Client ID: hr-portal-web +Client Type: OpenID Connect (公開客戶端) +``` + +### 後端 API +``` +URL: https://hr-api.ease.taipei +健康檢查: /health +狀態: ✅ 運行中 +API 文檔: /docs +``` + +### 前端配置 (.env) +```env +VITE_API_BASE_URL=https://hr-api.ease.taipei +VITE_KEYCLOAK_URL=https://auth.ease.taipei +VITE_KEYCLOAK_REALM=porscheworld +VITE_KEYCLOAK_CLIENT_ID=hr-portal-web +``` + +### 部署目標 +``` +主機: 10.1.0.254 (Ubuntu Server) +用戶: user +路徑: /home/user/hr-portal/frontend/ +網域: https://hr.ease.taipei +``` + +--- + +## 🎯 功能完成度 + +### 已完成功能 (95%) + +#### UI 組件庫 (9個) +- [x] Input - 文字輸入框 +- [x] Select - 下拉選單 +- [x] Textarea - 多行輸入 +- [x] Modal - 對話框 +- [x] Table - 資料表格 +- [x] Pagination - 分頁器 +- [x] Loading - 載入動畫 +- [x] EmptyState - 空狀態 +- [x] ConfirmDialog - 確認對話框 + +#### 員工管理 +- [x] 員工列表 (搜尋、篩選、分頁) +- [x] 員工詳情 (Tab 切換) +- [x] 新增員工 (表單驗證) +- [x] 編輯員工 +- [x] 密碼重設 (自動生成/手動) +- [x] 離職處理 (確認流程) +- [x] 自動創建帳號 (create_full) + - Keycloak SSO 帳號 + - 郵件帳號 + - NAS 網路硬碟 + +#### 組織管理 +- [x] 事業部 CRUD +- [x] 部門 CRUD +- [x] 經理指派 +- [x] 動態員工篩選 + +#### 資源管理 +- [x] 郵件帳號列表 (配額視覺化) +- [x] 網路硬碟列表 (配額視覺化) + +#### 系統整合 +- [x] Keycloak SSO 登入 +- [x] Token 自動刷新 +- [x] API 錯誤處理 +- [x] CORS 配置 +- [x] 表單驗證 (Zod) + +--- + +## 📋 部署步驟快速參考 + +### 🔥 最快速部署 (3 步驟) + +#### 1. 上傳 ZIP 包 +使用 WinSCP: +``` +本地: W:\DevOps-Workspace\hr-portal\frontend\hr-portal-frontend-deploy.zip +遠端: /home/user/hr-portal-frontend-deploy.zip +``` + +#### 2. SSH 解壓並部署 +```bash +cd /home/user +unzip -o hr-portal-frontend-deploy.zip -d hr-portal/frontend/ +cd hr-portal/frontend +docker-compose down && docker-compose build && docker-compose up -d +``` + +#### 3. 驗證 +```bash +docker-compose ps +curl -k https://hr.ease.taipei +``` + +瀏覽器訪問: **https://hr.ease.taipei** + +--- + +## 📚 部署文檔索引 + +### 核心文檔 +1. **[README.md](README.md)** - 專案總覽 +2. **[FEATURES_COMPLETE.md](FEATURES_COMPLETE.md)** - 功能完成清單 + +### 部署文檔 +3. **[DEPLOY_NOW.md](frontend/DEPLOY_NOW.md)** - 立即部署指南 ⭐ +4. **[QUICK_DEPLOY.md](frontend/QUICK_DEPLOY.md)** - 快速部署指令 +5. **[DEPLOYMENT.md](frontend/DEPLOYMENT.md)** - 完整部署手冊 +6. **[DEPLOY_CHECKLIST.md](DEPLOY_CHECKLIST.md)** - 部署檢查清單 + +### 配置文檔 +7. **[KEYCLOAK_SETUP.md](KEYCLOAK_SETUP.md)** - Keycloak 配置指南 + +### 驗證工具 +8. **[verify-deployment.sh](frontend/verify-deployment.sh)** - 部署驗證腳本 + +--- + +## 🛠️ 部署工具 + +### Windows 工具 +- **部署包**: `hr-portal-frontend-deploy.zip` (139 KB) +- **檔案傳輸**: WinSCP (推薦) 或 FileZilla +- **SSH 客戶端**: PuTTY 或 Windows Terminal + +### Ubuntu 腳本 +- **驗證腳本**: `verify-deployment.sh` + ```bash + # 上傳並執行 + chmod +x verify-deployment.sh + ./verify-deployment.sh + ``` + +--- + +## ✅ 部署前檢查清單 + +### 環境檢查 +- [x] 後端 API 運行: https://hr-api.ease.taipei/health +- [x] Keycloak 運行: https://auth.ease.taipei +- [x] Keycloak Client `hr-portal-web` 已創建 +- [x] Ubuntu 主機可連接: 10.1.0.254 +- [x] Traefik 容器運行中 +- [x] traefik-public 網路存在 + +### 構建檢查 +- [x] 前端構建成功 (440.49 KB) +- [x] TypeScript 編譯無錯誤 +- [x] 環境變數正確配置 +- [x] Keycloak Client ID: `hr-portal-web` + +### 檔案檢查 +- [x] Dockerfile 存在 +- [x] docker-compose.yml 存在 +- [x] dist/ 目錄完整 +- [x] 部署 ZIP 包已創建 + +--- + +## 🎯 部署後驗證清單 + +### 容器驗證 +- [ ] 容器運行: `docker-compose ps` +- [ ] 無錯誤日誌: `docker-compose logs` +- [ ] 在 traefik-public 網路中 +- [ ] Traefik 標籤正確 + +### HTTP 驗證 +- [ ] HTTP 200: `curl http://localhost:80` +- [ ] HTTPS 200: `curl -k https://hr.ease.taipei` +- [ ] HTTPS 證書有效 +- [ ] 可獲取 index.html + +### 應用驗證 +- [ ] 瀏覽器可訪問 https://hr.ease.taipei +- [ ] 重定向到 Keycloak 登入 +- [ ] SSO 登入成功 +- [ ] 顯示 HR Portal 首頁 +- [ ] 右上角顯示用戶姓名 + +### 功能驗證 +- [ ] 員工列表載入成功 +- [ ] 搜尋功能正常 +- [ ] 篩選功能正常 +- [ ] 分頁功能正常 +- [ ] 可點擊「新增員工」 +- [ ] API 調用無 CORS 錯誤 + +### 核心功能測試 +- [ ] **新增員工測試** + - [ ] 填寫表單 + - [ ] 勾選「自動創建帳號」 + - [ ] 提交成功 + - [ ] 檢查 Keycloak 用戶已創建 + - [ ] 檢查郵件帳號已創建 + - [ ] 檢查 NAS 硬碟已創建 + +--- + +## 📊 預期結果 + +### 成功指標 + +#### 容器層 +```bash +$ docker-compose ps +NAME STATUS +hr-portal-frontend Up +``` + +#### HTTP 層 +```bash +$ curl -I http://localhost:80 +HTTP/1.1 200 OK + +$ curl -k -I https://hr.ease.taipei +HTTP/2 200 +``` + +#### 應用層 +- ✅ 瀏覽器顯示 HR Portal 登入重定向 +- ✅ Keycloak 登入頁面載入 +- ✅ 登入後跳轉回 HR Portal +- ✅ 首頁載入成功 +- ✅ 員工列表載入成功 + +--- + +## 🐛 常見問題快速參考 + +### 容器無法啟動 +```bash +docker-compose logs hr-portal-frontend +docker-compose build --no-cache +docker-compose up -d +``` + +### 無法訪問網站 +```bash +# 檢查 Traefik +docker ps | grep traefik +docker logs traefik | grep hr-portal + +# 檢查網路 +docker network inspect traefik-public | grep hr-portal +``` + +### Keycloak 登入失敗 +- 檢查 Client ID: 應為 `hr-portal-web` +- 檢查 Redirect URIs: 應包含 `https://hr.ease.taipei/*` +- 檢查 Web Origins: 應包含 `https://hr.ease.taipei` + +### API CORS 錯誤 +- 確認後端 CORS 配置包含 `https://hr.ease.taipei` +- 檢查後端日誌 + +--- + +## 🎊 部署成功後 + +### 立即測試 +1. **登入測試**: 使用測試帳號登入 +2. **列表測試**: 查看員工列表 +3. **搜尋測試**: 測試搜尋功能 +4. **新增測試**: 創建測試員工 (不勾選 create_full) +5. **自動創建測試**: 創建員工並勾選 create_full + +### 後續優化 (建議順序) +1. **Toast 通知** (替換 alert) +2. **審計日誌 UI** +3. **權限管理 UI** +4. **批量匯入功能** +5. **報表功能** + +--- + +## 📞 支持資源 + +### 技術文檔 +- **API 文檔**: https://hr-api.ease.taipei/docs +- **Keycloak Admin**: https://auth.ease.taipei + +### 聯絡方式 +- **技術支持**: porsche.chen@gmail.com + +--- + +## 🚀 準備就緒! + +**所有準備工作已完成,可以立即開始部署!** + +**推薦部署方式**: +使用 **DEPLOY_NOW.md 方式 1 (ZIP 部署包)**,只需 3 個步驟即可完成。 + +**部署文檔**: [frontend/DEPLOY_NOW.md](frontend/DEPLOY_NOW.md) + +--- + +**Good Luck!** 🎉 diff --git a/DEPLOY_CHECKLIST.md b/DEPLOY_CHECKLIST.md new file mode 100644 index 0000000..d5c6ded --- /dev/null +++ b/DEPLOY_CHECKLIST.md @@ -0,0 +1,350 @@ +# HR Portal 部署清單 + +## ✅ 已完成項目 + +### 1. 環境配置 ✓ + +- [x] **Keycloak 配置** + - Realm: `porscheworld` + - Client ID: `hr-portal-web` + - URL: https://auth.ease.taipei + +- [x] **後端 API** + - URL: https://hr-api.ease.taipei + - 狀態: 運行中 (健康檢查通過) + - 資料庫: PostgreSQL 16 + +- [x] **前端配置** + - 環境變數已設定 (.env) + - 構建成功 (440.49 kB) + - Keycloak Client ID: `hr-portal-web` + +### 2. 功能開發 ✓ + +- [x] UI 組件庫 (9個組件) +- [x] 員工管理 (CRUD + 搜尋篩選) +- [x] 組織管理 (事業部/部門) +- [x] 資源管理 (郵件/硬碟) +- [x] 密碼重設功能 +- [x] 離職處理功能 +- [x] 自動創建帳號 (create_full) + +### 3. 系統整合 ✓ + +- [x] Keycloak SSO 整合 +- [x] API Token 自動刷新 +- [x] CORS 配置 +- [x] 表單驗證 (Zod) +- [x] 錯誤處理 + +--- + +## 📋 部署步驟 + +### 步驟 1: 驗證 Keycloak 配置 + +登入 Keycloak Admin Console: https://auth.ease.taipei + +1. **檢查 Realm**: `porscheworld` +2. **檢查 Client**: `hr-portal-web` +3. **驗證 Redirect URIs**: + ``` + https://hr.ease.taipei/* + http://localhost:3000/* (開發用) + ``` +4. **驗證 Web Origins**: + ``` + https://hr.ease.taipei + http://localhost:3000 + ``` + +### 步驟 2: 構建前端 + +在 Windows 上執行: +```powershell +cd W:\DevOps-Workspace\hr-portal\frontend +npm run build +``` + +驗證構建產物: +``` +✓ dist/index.html (0.76 kB) +✓ dist/assets/index-B6AIDaLe.css (22.40 kB) +✓ dist/assets/index-C5znSMh-.js (440.49 kB) +``` + +### 步驟 3: 複製檔案到 Ubuntu 主機 + +使用 WinSCP 或 scp: +```powershell +# 連接資訊 +主機: 10.1.0.254 +用戶: user +目標路徑: /home/user/hr-portal/frontend/ + +# 需要複製的檔案 +- dist/ (整個目錄) +- Dockerfile +- docker-compose.yml +``` + +或使用命令列: +```powershell +scp -r dist Dockerfile docker-compose.yml user@10.1.0.254:/home/user/hr-portal/frontend/ +``` + +### 步驟 4: SSH 到 Ubuntu 並部署 + +```bash +ssh user@10.1.0.254 + +# 切換目錄 +cd /home/user/hr-portal/frontend + +# 停止舊容器 (如果存在) +docker-compose down + +# 構建 Docker 鏡像 +docker-compose build + +# 啟動容器 +docker-compose up -d + +# 檢查容器狀態 +docker-compose ps +# 應該看到 hr-portal-frontend 容器在運行 +``` + +### 步驟 5: 驗證部署 + +#### 5.1 檢查容器日誌 +```bash +docker-compose logs -f hr-portal-frontend +``` + +應該看到 Nginx 啟動訊息,沒有錯誤。 + +#### 5.2 測試內部訪問 +```bash +curl -I http://localhost:80 +``` + +應該返回 `HTTP/1.1 200 OK` + +#### 5.3 測試 Traefik 路由 +```bash +curl -k -I https://hr.ease.taipei +``` + +應該返回 `HTTP/2 200` + +#### 5.4 瀏覽器測試 + +1. 訪問: `https://hr.ease.taipei` +2. 應自動重定向到 Keycloak 登入頁面 +3. 輸入測試帳號登入 +4. 登入成功後應跳轉回 HR Portal 首頁 + +### 步驟 6: 測試核心功能 + +#### 6.1 SSO 登入測試 +- [ ] 可以訪問 https://hr.ease.taipei +- [ ] 重定向到 Keycloak 登入頁面 +- [ ] 使用測試帳號登入成功 +- [ ] 跳轉回 HR Portal 首頁 +- [ ] 可以看到用戶姓名 (右上角) + +#### 6.2 員工管理測試 +- [ ] 訪問「員工管理」頁面 +- [ ] 可以看到員工列表 +- [ ] 搜尋功能正常 +- [ ] 篩選功能正常 +- [ ] 分頁功能正常 + +#### 6.3 新增員工測試 (重要!) +- [ ] 點擊「新增員工」 +- [ ] 填寫表單 +- [ ] 勾選「自動創建 Keycloak 帳號、郵件帳號和 NAS 網路硬碟」 +- [ ] 提交表單 +- [ ] 檢查是否成功創建 +- [ ] 驗證 Keycloak 是否創建用戶 +- [ ] 驗證郵件帳號是否創建 +- [ ] 驗證 NAS 硬碟是否創建 + +#### 6.4 API 調用測試 +打開瀏覽器 Developer Tools → Network 標籤: +- [ ] API 請求正常 (200 OK) +- [ ] 請求包含 Authorization header +- [ ] Token 自動刷新正常 +- [ ] 無 CORS 錯誤 + +--- + +## 🔧 Traefik 路由配置 + +### 檢查 Traefik 路由 + +```bash +# 檢查 Traefik 容器 +docker ps | grep traefik + +# 檢查 hr-portal-frontend 容器的標籤 +docker inspect hr-portal-frontend | grep -A 10 Labels + +# 檢查網路連接 +docker network inspect traefik-public | grep hr-portal +``` + +### 預期的 Traefik 標籤 + +docker-compose.yml 中已包含: +```yaml +labels: + - "traefik.enable=true" + - "traefik.http.routers.hr-portal.rule=Host(`hr.ease.taipei`)" + - "traefik.http.routers.hr-portal.entrypoints=websecure" + - "traefik.http.routers.hr-portal.tls=true" + - "traefik.http.routers.hr-portal.tls.certresolver=letsencrypt" + - "traefik.http.services.hr-portal.loadbalancer.server.port=80" +``` + +--- + +## 🐛 常見問題排查 + +### 問題 1: 無法訪問 https://hr.ease.taipei + +**排查步驟**: +1. 檢查容器是否運行: `docker-compose ps` +2. 檢查 Traefik 日誌: `docker logs traefik` +3. 檢查 DNS 解析: `nslookup hr.ease.taipei` +4. 檢查網路: `docker network ls` + +### 問題 2: Keycloak 登入失敗 + +**排查步驟**: +1. 檢查 Client ID 是否正確: `hr-portal-web` +2. 檢查 Redirect URIs 是否包含 `https://hr.ease.taipei/*` +3. 查看瀏覽器 Console 錯誤訊息 +4. 檢查 Keycloak 服務: `curl https://auth.ease.taipei/realms/porscheworld` + +### 問題 3: API 調用失敗 (CORS 錯誤) + +**排查步驟**: +1. 檢查後端 CORS 配置 +2. 確認 `https://hr.ease.taipei` 在 allowed origins 列表中 +3. 檢查後端日誌 +4. 測試 API 健康檢查: `curl -k https://hr-api.ease.taipei/health` + +### 問題 4: 自動創建帳號失敗 + +**排查步驟**: +1. 檢查後端日誌: `docker logs hr-backend` +2. 確認 Keycloak Admin 權限 +3. 確認郵件伺服器 API 可訪問 +4. 確認 NAS API 可訪問 +5. 檢查資料庫記錄是否創建 + +--- + +## 📊 監控與維護 + +### 日誌查看 + +```bash +# 前端容器日誌 +docker-compose logs -f hr-portal-frontend + +# 後端 API 日誌 +docker logs -f hr-backend + +# Keycloak 日誌 +docker logs -f keycloak + +# Traefik 日誌 +docker logs -f traefik +``` + +### 容器狀態 + +```bash +# 查看所有 HR Portal 相關容器 +docker ps --filter "name=hr" + +# 查看容器資源使用 +docker stats hr-portal-frontend hr-backend +``` + +### 更新部署 + +當代碼更新時: +```bash +# 1. 在 Windows 構建 +cd W:\DevOps-Workspace\hr-portal\frontend +npm run build + +# 2. 複製到 Ubuntu +scp -r dist/* user@10.1.0.254:/home/user/hr-portal/frontend/dist/ + +# 3. 重啟容器 +ssh user@10.1.0.254 'cd /home/user/hr-portal/frontend && docker-compose restart' +``` + +--- + +## 🎯 下一步計劃 + +### 短期優化 (本週完成) + +1. **Toast 通知系統** (替換 alert) + - 安裝: `npm install react-hot-toast` + - 整合到所有操作回饋 + +2. **測試自動創建帳號流程** + - 創建測試員工 + - 驗證 Keycloak 帳號 + - 驗證郵件帳號 + - 驗證 NAS 硬碟 + +3. **完善錯誤處理** + - API 錯誤訊息優化 + - 網路錯誤處理 + - 表單驗證訊息 + +### 中期擴展 (2-4週) + +1. **審計日誌 UI** +2. **權限管理 UI** +3. **批量匯入員工** +4. **報表功能** + +--- + +## ✅ 部署完成確認 + +部署成功後,應滿足以下所有條件: + +- [ ] ✅ 容器 `hr-portal-frontend` 運行中 +- [ ] ✅ 可訪問 https://hr.ease.taipei +- [ ] ✅ HTTPS 證書有效 (Let's Encrypt) +- [ ] ✅ Keycloak SSO 登入正常 +- [ ] ✅ 可看到員工列表 +- [ ] ✅ 搜尋、篩選、分頁功能正常 +- [ ] ✅ 可新增員工 +- [ ] ✅ 自動創建帳號功能正常 (create_full) +- [ ] ✅ API 調用正常 (無 CORS 錯誤) +- [ ] ✅ Token 自動刷新正常 + +--- + +## 📞 支持資源 + +- **部署文檔**: [frontend/DEPLOYMENT.md](frontend/DEPLOYMENT.md) +- **Keycloak 配置**: [KEYCLOAK_SETUP.md](KEYCLOAK_SETUP.md) +- **功能清單**: [FEATURES_COMPLETE.md](FEATURES_COMPLETE.md) +- **API 文檔**: https://hr-api.ease.taipei/docs + +--- + +**部署準備**: ✅ 就緒 +**現在可以開始部署了!** 🚀 diff --git a/DEVELOPMENT_GUIDE.md b/DEVELOPMENT_GUIDE.md new file mode 100644 index 0000000..d337fb3 --- /dev/null +++ b/DEVELOPMENT_GUIDE.md @@ -0,0 +1,615 @@ +# HR Portal v2.0 開發指南 + +本文件提供 HR Portal 專案的開發規範、最佳實踐和常見操作指南。 + +--- + +## 📋 目錄 + +1. [環境設置](#環境設置) +2. [開發流程](#開發流程) +3. [代碼規範](#代碼規範) +4. [API 開發指南](#api-開發指南) +5. [資料庫操作](#資料庫操作) +6. [測試指南](#測試指南) +7. [常見問題](#常見問題) + +--- + +## 環境設置 + +### 前置需求 + +- Python 3.11+ +- Node.js 20+ +- Docker 24+ +- PostgreSQL 16+ (或使用 Docker) +- Git + +### 後端環境設置 + +```bash +# 1. 克隆專案 +cd W:\DevOps-Workspace\3.Develop\4.HR_Portal + +# 2. 創建 Python 虛擬環境 +cd backend +python -m venv venv + +# 3. 啟動虛擬環境 +# Windows: +venv\Scripts\activate +# Linux/Mac: +source venv/bin/activate + +# 4. 安裝依賴 +pip install -r requirements.txt + +# 5. 配置環境變數 +cp .env.example .env +# 編輯 .env 填入實際值 + +# 6. 啟動資料庫 (Docker) +cd ../database +docker-compose up -d +cd ../backend + +# 7. 啟動開發伺服器 +uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 +``` + +### 資料庫初始化 + +```bash +# 方式 1: SQLAlchemy 自動創建 (開發環境) +# 啟動 FastAPI 時會自動創建表格 + +# 方式 2: 手動執行 SQL (生產環境推薦) +cd database +docker exec -i hr-portal-db-test psql -U hr_admin -d hr_portal < schema.sql + +# 測試資料庫 +docker exec -i hr-portal-db-test psql -U hr_admin -d hr_portal < test_schema.sql +``` + +### 前端環境設置 (待創建) + +```bash +# 待前端專案建立後補充 +``` + +--- + +## 開發流程 + +### 1. 創建新功能 + +#### Step 1: 規劃 +1. 閱讀相關設計文件 (`2.專案設計區/4.HR_Portal/`) +2. 確認需求和業務規則 +3. 設計 API 端點和資料結構 + +#### Step 2: 資料庫 +1. 更新 Schema (如需要) +2. 創建 SQLAlchemy Model +3. 測試 Model 關聯 + +#### Step 3: 資料驗證 +1. 創建 Pydantic Schemas +2. 定義 Create/Update/Response Schemas +3. 添加驗證規則和範例 + +#### Step 4: API 開發 +1. 創建 API 路由文件 +2. 實作端點邏輯 +3. 添加錯誤處理 +4. 測試 API + +#### Step 5: 文檔 +1. 更新 API 文檔 +2. 添加使用範例 +3. 更新 PROGRESS.md + +### 2. Git 工作流程 + +```bash +# 1. 創建功能分支 +git checkout -b feature/your-feature-name + +# 2. 開發和提交 +git add . +git commit -m "feat: add your feature description" + +# 3. 推送到遠端 +git push origin feature/your-feature-name + +# 4. 創建 Pull Request +# 在 GitHub/Gitea 上創建 PR + +# 5. Code Review 後合併 +git checkout main +git merge feature/your-feature-name +git push origin main +``` + +### 3. Commit 訊息規範 + +遵循 [Conventional Commits](https://www.conventionalcommits.org/): + +``` +(): + + + +