# Chat Room Module Documentation ## 模組概述 `app/modules/chat_room` 模組提供生產線異常事件協作管理功能,允許團隊成員建立事件室、管理成員權限、追蹤事件狀態,並進行即時協作。 --- ## 模組架構 ``` app/modules/chat_room/ ├── __init__.py # 模組入口,匯出 router ├── models.py # SQLAlchemy 資料模型 ├── schemas.py # Pydantic 請求/回應模型 ├── router.py # FastAPI 路由定義 ├── dependencies.py # 依賴注入與權限驗證 └── services/ ├── __init__.py ├── room_service.py # 房間業務邏輯 ├── membership_service.py # 成員管理業務邏輯 └── template_service.py # 範本管理業務邏輯 ``` --- ## 核心概念 ### 1. 房間生命週期 事件室從建立到封存的完整生命週期: ``` ┌─────────────┐ │ 建立房間 │ ← 使用者建立新事件室 └──────┬──────┘ ↓ ┌─────────────┐ │ ACTIVE │ ← 事件進行中,可新增成員、更新資訊 │ (活躍) │ └──────┬──────┘ ↓ (事件處理完成) ┌─────────────┐ │ RESOLVED │ ← 事件已解決,填寫解決方案 │ (已解決) │ └──────┬──────┘ ↓ (確認可封存) ┌─────────────┐ │ ARCHIVED │ ← 事件已封存,僅供查詢 │ (已封存) │ └─────────────┘ ``` **狀態轉換規則**: - 只能單向前進:ACTIVE → RESOLVED → ARCHIVED - 不允許跳過狀態或反向轉換 - 每次狀態變更都會更新 `last_activity_at` **關鍵時間戳記**: - `created_at`: 房間建立時間 - `resolved_at`: 標記為已解決的時間 - `archived_at`: 封存時間(軟刪除) - `last_activity_at`: 最後活動時間(用於排序) --- ### 2. 權限模型 #### 2.1 角色定義 | 角色 | 說明 | 權限 | |-----|-----|-----| | **OWNER** | 擁有者 | - 完全控制權
- 可更新房間資訊
- 可管理所有成員
- 可轉移所有權
- 可刪除房間 | | **EDITOR** | 編輯者 | - 讀寫權限
- 可新增 VIEWER 成員
- 不可變更房間狀態
- 不可管理 OWNER/EDITOR | | **VIEWER** | 檢視者 | - 僅讀取權限
- 可查看房間資訊與成員
- 無法進行任何修改 | | **ADMIN** | 系統管理員 | - 覆寫所有限制
- 可存取所有房間
- 執行任何操作 | #### 2.2 系統管理員 **管理員帳號**: `ymirliu@panjit.com.tw` **特殊權限**: 1. 查看系統中所有房間(即使非成員) 2. 覆寫所有角色限制 3. 強制執行任何操作 4. 不受成員資格限制 **實作位置**: - `app/modules/chat_room/services/membership_service.py:is_system_admin()` - 硬編碼檢查信箱是否為 `ymirliu@panjit.com.tw` #### 2.3 權限檢查流程 ```python # 在 dependencies.py 中的權限檢查流程 def require_room_permission(permission: str): """ 1. 檢查是否為系統管理員 → 通過 2. 檢查使用者是否為房間成員 → 否則拒絕 3. 根據角色檢查特定權限 → 通過/拒絕 """ async def dependency( room_id: str, current_user: dict = Depends(get_current_user), db: Session = Depends(get_db) ): user_email = current_user["username"] # 管理員覆寫 if membership_service.is_system_admin(user_email): return None # 檢查成員資格 role = membership_service.get_user_role_in_room(db, room_id, user_email) if not role: raise HTTPException(status_code=403, detail="Not a room member") # 檢查權限 if not has_permission(role, permission): raise HTTPException(status_code=403, detail="Insufficient permissions") return None return dependency ``` --- ### 3. 所有權轉移機制 ⭐ #### 3.1 轉移流程 ``` 使用者需求:現有 owner 指派給新 owner 實作步驟: 1. 驗證當前使用者為 OWNER 2. 驗證新 owner 為現有房間成員 3. 執行角色變更: - 原 owner → EDITOR - 新 owner → OWNER 4. 記錄稽核資訊: - ownership_transferred_at: 轉移時間 - ownership_transferred_by: 執行轉移的使用者 ``` #### 3.2 程式碼範例 ```python # services/membership_service.py def transfer_ownership( self, db: Session, room_id: str, current_owner_id: str, new_owner_id: str ) -> bool: """轉移房間所有權""" # 1. 驗證新 owner 是房間成員 new_owner_member = db.query(RoomMember).filter( RoomMember.room_id == room_id, RoomMember.user_id == new_owner_id, RoomMember.removed_at.is_(None) ).first() if not new_owner_member: return False # 2. 取得原 owner current_owner = db.query(RoomMember).filter( RoomMember.room_id == room_id, RoomMember.user_id == current_owner_id, RoomMember.role == MemberRole.OWNER ).first() if not current_owner: return False # 3. 執行角色交換 current_owner.role = MemberRole.EDITOR new_owner_member.role = MemberRole.OWNER # 4. 記錄稽核資訊 room = db.query(IncidentRoom).filter( IncidentRoom.room_id == room_id ).first() room.ownership_transferred_at = datetime.utcnow() room.ownership_transferred_by = current_owner_id room.last_updated_at = datetime.utcnow() db.commit() return True ``` #### 3.3 API 使用範例 ```bash POST /api/rooms/{room_id}/transfer-ownership Authorization: Bearer Content-Type: application/json { "new_owner_id": "engineer@panjit.com.tw" } # 回應 { "message": "Ownership transferred successfully" } # 效果: # - engineer@panjit.com.tw 成為新 OWNER # - 原 OWNER 降級為 EDITOR # - 記錄於 ownership_transferred_at 和 ownership_transferred_by ``` --- ### 4. 成員管理 #### 4.1 軟刪除機制 成員採用軟刪除設計,不實際刪除記錄: ```python # models.py class RoomMember(Base): removed_at = Column(DateTime, nullable=True) # NULL = 活躍成員 # 唯一性約束:同一房間中,同一使用者只能有一個活躍成員記錄 __table_args__ = ( Index('ix_room_members_active', 'room_id', 'user_id', postgresql_where=text('removed_at IS NULL')), ) ``` **優點**: - 保留歷史記錄 - 支援稽核追蹤 - 可恢復誤刪的成員 #### 4.2 成員計數同步 `member_count` 欄位自動同步: ```python def add_member(...): # 新增成員 member = RoomMember(...) db.add(member) # 更新計數 room.member_count += 1 room.last_activity_at = datetime.utcnow() db.commit() def remove_member(...): # 軟刪除 member.removed_at = datetime.utcnow() # 更新計數 room.member_count -= 1 room.last_activity_at = datetime.utcnow() db.commit() ``` --- ### 5. 範本系統 #### 5.1 預設範本 系統提供三個預設範本,在應用啟動時自動初始化: ```python # services/template_service.py DEFAULT_TEMPLATES = [ { "name": "equipment_failure", "description": "設備故障事件需要立即處理", "incident_type": IncidentType.EQUIPMENT_FAILURE, "default_severity": SeverityLevel.HIGH, "default_members": [ {"user_id": "maintenance_team@panjit.com.tw", "role": "editor"}, {"user_id": "engineering@panjit.com.tw", "role": "viewer"} ] }, { "name": "material_shortage", "description": "物料短缺影響生產", "incident_type": IncidentType.MATERIAL_SHORTAGE, "default_severity": SeverityLevel.MEDIUM, "default_members": [ {"user_id": "procurement@panjit.com.tw", "role": "editor"}, {"user_id": "logistics@panjit.com.tw", "role": "editor"} ] }, { "name": "quality_issue", "description": "品質問題需要調查", "incident_type": IncidentType.QUALITY_ISSUE, "default_severity": SeverityLevel.HIGH, "default_members": [ {"user_id": "quality_team@panjit.com.tw", "role": "editor"}, {"user_id": "production_manager@panjit.com.tw", "role": "viewer"} ] } ] ``` #### 5.2 使用範本建立房間 ```python # router.py - create_room endpoint if room_data.template: # 查詢範本 template = template_service.get_template_by_name(db, room_data.template) if template: # 從範本建立房間(自動設定類型、嚴重度、預設成員) room = template_service.create_room_from_template( db, template.template_id, user_email, room_data.title, room_data.location, room_data.description ) ``` **優勢**: - 快速建立標準化事件室 - 自動新增相關人員 - 確保一致性 --- ## 整合範例 ### 範例 1: 在其他模組中查詢使用者的房間 ```python from app.modules.chat_room.services.membership_service import membership_service def get_user_active_rooms(db: Session, user_email: str): """取得使用者所有活躍房間""" from app.modules.chat_room.models import RoomStatus from app.modules.chat_room.schemas import RoomFilterParams from app.modules.chat_room.services.room_service import room_service filters = RoomFilterParams( status=RoomStatus.ACTIVE, limit=100, offset=0 ) rooms, total = room_service.list_user_rooms( db, user_email, filters, is_admin=membership_service.is_system_admin(user_email) ) return rooms ``` ### 範例 2: 檢查使用者是否有特定房間的權限 ```python from app.modules.chat_room.services.membership_service import membership_service from app.modules.chat_room.models import MemberRole def can_user_edit_room(db: Session, room_id: str, user_email: str) -> bool: """檢查使用者是否可編輯房間""" # 管理員直接通過 if membership_service.is_system_admin(user_email): return True # 檢查角色 role = membership_service.get_user_role_in_room(db, room_id, user_email) return role in [MemberRole.OWNER, MemberRole.EDITOR] ``` ### 範例 3: 建立帶有自訂成員的房間 ```python from app.modules.chat_room.services.room_service import room_service from app.modules.chat_room.services.membership_service import membership_service from app.modules.chat_room.schemas import CreateRoomRequest from app.modules.chat_room.models import MemberRole, IncidentType, SeverityLevel def create_custom_incident_room( db: Session, creator_email: str, title: str, additional_members: list[tuple[str, MemberRole]] ): """建立自訂成員的事件室""" # 1. 建立房間 room_data = CreateRoomRequest( title=title, incident_type=IncidentType.OTHER, severity=SeverityLevel.MEDIUM, location="", description="" ) room = room_service.create_room(db, creator_email, room_data) # 2. 新增額外成員 for user_email, role in additional_members: membership_service.add_member( db, room.room_id, user_email, role, added_by=creator_email ) return room ``` --- ## 資料庫查詢優化 ### 索引策略 ```sql -- 房間查詢優化 CREATE INDEX ix_incident_rooms_status_created ON incident_rooms(status, created_at); CREATE INDEX ix_incident_rooms_created_by ON incident_rooms(created_by); -- 成員查詢優化 CREATE INDEX ix_room_members_room_user ON room_members(room_id, user_id); CREATE INDEX ix_room_members_user ON room_members(user_id); -- 範本查詢優化 CREATE UNIQUE INDEX ix_room_templates_name ON room_templates(name); ``` ### 常見查詢模式 ```python # 1. 取得使用者參與的所有房間(已優化) user_rooms = db.query(IncidentRoom).join( RoomMember, and_( RoomMember.room_id == IncidentRoom.room_id, RoomMember.user_id == user_email, RoomMember.removed_at.is_(None) ) ).filter( IncidentRoom.archived_at.is_(None) ).order_by( IncidentRoom.last_activity_at.desc() ).all() # 2. 取得房間所有活躍成員(已優化) active_members = db.query(RoomMember).filter( RoomMember.room_id == room_id, RoomMember.removed_at.is_(None) ).all() # 3. 檢查使用者權限(已優化) member = db.query(RoomMember).filter( RoomMember.room_id == room_id, RoomMember.user_id == user_email, RoomMember.removed_at.is_(None) ).first() ``` --- ## 未來擴展 ### WebSocket 整合準備 模組已為 WebSocket 即時通訊預留設計空間: ```python # 未來可實作: # - 房間訊息廣播 # - 成員上線狀態 # - 即時通知 # - 協作編輯 # 建議架構: # app/modules/chat_room/websocket.py class RoomWebSocketManager: def __init__(self): self.active_connections: dict[str, list[WebSocket]] = {} async def connect(self, room_id: str, websocket: WebSocket): """連接到房間頻道""" pass async def broadcast(self, room_id: str, message: dict): """廣播訊息到房間所有成員""" pass ``` ### 稽核日誌 建議新增完整的稽核日誌表: ```python # 未來可實作: class RoomAuditLog(Base): __tablename__ = "room_audit_logs" log_id = Column(String(36), primary_key=True) room_id = Column(String(36), ForeignKey("incident_rooms.room_id")) action = Column(String(50)) # created, updated, member_added, etc. actor = Column(String(255)) # 執行操作的使用者 details = Column(JSON) # 詳細變更內容 timestamp = Column(DateTime, default=datetime.utcnow) ``` --- ## 測試建議 ### 單元測試重點 ```python # tests/test_chat_room/test_membership_service.py def test_ownership_transfer(): """測試所有權轉移""" # 1. 建立房間與成員 # 2. 執行轉移 # 3. 驗證角色變更 # 4. 驗證稽核記錄 def test_admin_override(): """測試管理員覆寫""" # 1. 使用非成員的管理員帳號 # 2. 驗證可執行所有操作 def test_permission_enforcement(): """測試權限限制""" # 1. VIEWER 嘗試修改 → 失敗 # 2. EDITOR 嘗試新增 OWNER → 失敗 # 3. OWNER 執行任何操作 → 成功 ``` ### 整合測試重點 ```python # tests/test_chat_room/test_api_endpoints.py def test_full_room_lifecycle(): """測試完整房間生命週期""" # 1. 建立 → 2. 新增成員 → 3. 更新 → 4. 解決 → 5. 封存 def test_ownership_transfer_api(): """測試 API 層級的所有權轉移""" # 包含認證、權限檢查、業務邏輯 ``` --- ## 總結 Chat Room 模組提供了一個完整的事件協作管理系統,具備: ✅ **角色權限系統** - OWNER/EDITOR/VIEWER + ADMIN 覆寫 ✅ **所有權轉移** - 支援動態變更房間擁有者 ✅ **生命週期管理** - ACTIVE → RESOLVED → ARCHIVED ✅ **範本系統** - 快速建立標準化事件室 ✅ **稽核追蹤** - 記錄所有關鍵操作 ✅ **擴展性** - 為 WebSocket 與稽核日誌預留設計空間