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,111 @@
"""
SystemFunction Model
系統功能明細檔
"""
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, JSON
from sqlalchemy.sql import func
from app.db.base import Base
class SystemFunction(Base):
"""系統功能明細"""
__tablename__ = "system_functions"
# 1. 資料編號 (PK, 自動編號從 10 開始, 1~9 為功能設定編號)
id = Column(Integer, primary_key=True, index=True, comment="資料編號")
# 2. 系統功能代碼/功能英文名稱
code = Column(String(200), nullable=False, index=True, comment="系統功能代碼/功能英文名稱")
# 3. 上層功能代碼 (0 為初始層)
upper_function_id = Column(
Integer,
nullable=False,
server_default="0",
index=True,
comment="上層功能代碼 (0為初始層)"
)
# 4. 系統功能中文名稱
name = Column(String(200), nullable=False, comment="系統功能中文名稱")
# 5. 系統功能類型 (1:node, 2:function)
function_type = Column(
Integer,
nullable=False,
index=True,
comment="系統功能類型 (1:node, 2:function)"
)
# 6. 系統功能次序
order = Column(Integer, nullable=False, comment="系統功能次序")
# 7. 功能圖示
function_icon = Column(
String(200),
nullable=False,
server_default="",
comment="功能圖示"
)
# 8. 功能模組名稱 (function_type=2 必填)
module_code = Column(
String(200),
nullable=True,
comment="功能模組名稱 (function_type=2 必填)"
)
# 9. 模組項目 (JSON: [View, Create, Read, Update, Delete, Print, File])
module_functions = Column(
JSON,
nullable=False,
server_default="[]",
comment="模組項目 (View,Create,Read,Update,Delete,Print,File)"
)
# 10. 說明 (富文本格式)
description = Column(
Text,
nullable=False,
server_default="",
comment="說明 (富文本格式)"
)
# 11. 系統管理
is_mana = Column(
Boolean,
nullable=False,
server_default="true",
comment="系統管理"
)
# 12. 啟用
is_active = Column(
Boolean,
nullable=False,
server_default="true",
index=True,
comment="啟用"
)
# 13. 資料建立者
edit_by = Column(Integer, nullable=False, comment="資料建立者")
# 14. 資料最新建立時間
created_at = Column(
DateTime(timezone=True),
nullable=False,
server_default=func.now(),
comment="資料最新建立時間"
)
# 15. 資料最新修改時間
updated_at = Column(
DateTime(timezone=True),
nullable=True,
onupdate=func.now(),
comment="資料最新修改時間"
)
def __repr__(self):
return f"<SystemFunction(id={self.id}, code={self.code}, name={self.name})>"