# 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 與稽核日誌預留設計空間