feat: add service worker for push notifications and update room documentation
This commit is contained in:
parent
6f6f57f062
commit
779aaba575
51
public/sw.js
Normal file
51
public/sw.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Service Worker for Web Push Notifications
|
||||||
|
const CACHE_NAME = 'app-v1';
|
||||||
|
|
||||||
|
self.addEventListener('push', (event) => {
|
||||||
|
if (!event.data) return;
|
||||||
|
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = event.data.json();
|
||||||
|
} catch {
|
||||||
|
data = { title: 'Notification', body: event.data.text() };
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
body: data.body || '',
|
||||||
|
icon: data.icon || '/icon.png',
|
||||||
|
badge: '/badge.png',
|
||||||
|
data: { url: data.url || '/' },
|
||||||
|
vibrate: [200, 100, 200],
|
||||||
|
requireInteraction: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
event.waitUntil(
|
||||||
|
self.registration.showNotification(data.title || 'App Notification', options)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('notificationclick', (event) => {
|
||||||
|
event.notification.close();
|
||||||
|
|
||||||
|
const url = event.notification.data?.url || '/';
|
||||||
|
|
||||||
|
event.waitUntil(
|
||||||
|
self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clients) => {
|
||||||
|
for (const client of clients) {
|
||||||
|
if (client.url === url && 'focus' in client) {
|
||||||
|
return client.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.clients.openWindow(url);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('install', () => {
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
event.waitUntil(self.clients.claim());
|
||||||
|
});
|
||||||
814
room.md
Normal file
814
room.md
Normal file
@ -0,0 +1,814 @@
|
|||||||
|
# Room 模块设计文档
|
||||||
|
|
||||||
|
## 1. 概述
|
||||||
|
|
||||||
|
`Room` 模块是本系统核心的协作与消息通信功能模块,提供稳定、高效、可扩展的实时消息平台。系统采用 Rust (Actix-web) 后端 + React 19 前端的技术栈,通过 WebSocket 实现实时通信,集成了 AI 代理进行智能协作。
|
||||||
|
|
||||||
|
### 技术栈
|
||||||
|
- **后端**: Rust + Actix-web + SeaORM + Redis + NATS
|
||||||
|
- **前端**: React 19 + TypeScript + Tailwind CSS
|
||||||
|
- **实时通信**: WebSocket (自定义协议)
|
||||||
|
- **消息队列**: NATS (事件分发)
|
||||||
|
- **缓存**: Redis (序列号管理、去重)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 数据模型
|
||||||
|
|
||||||
|
### 2.1 核心表结构
|
||||||
|
|
||||||
|
#### `room` - 房间表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | UUID (v7) | 主键,时间排序 |
|
||||||
|
| project | UUID | 所属项目 |
|
||||||
|
| room_name | VARCHAR(128) | 房间名称 |
|
||||||
|
| public | BOOLEAN | 是否公开房间 |
|
||||||
|
| category | UUID (nullable) | 所属分类 |
|
||||||
|
| created_by | UUID | 创建者 |
|
||||||
|
| created_at | TIMESTAMPTZ | 创建时间 |
|
||||||
|
| last_msg_at | TIMESTAMPTZ | 最后消息时间 |
|
||||||
|
|
||||||
|
#### `room_message` - 消息表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | UUID (v7) | 主键 |
|
||||||
|
| seq | BIGINT | 全局序列号(递增) |
|
||||||
|
| room | UUID | 所属房间 |
|
||||||
|
| sender_type | ENUM | `member` / `ai` / `system` |
|
||||||
|
| sender_id | UUID (nullable) | 发送者 ID |
|
||||||
|
| thread | UUID (nullable) | 所属线程 |
|
||||||
|
| in_reply_to | UUID (nullable) | 回复的消息 ID |
|
||||||
|
| content | TEXT | 消息内容 |
|
||||||
|
| content_type | ENUM | `text` / `markdown` / `code` / `mention` |
|
||||||
|
| edited_at | TIMESTAMPTZ (nullable) | 编辑时间 |
|
||||||
|
| send_at | TIMESTAMPTZ | 发送时间 |
|
||||||
|
| revoked | TIMESTAMPTZ (nullable) | 撤回时间 |
|
||||||
|
| revoked_by | UUID (nullable) | 撤回操作者 |
|
||||||
|
|
||||||
|
#### `room_member` - 房间成员表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| room | UUID | 房间 ID |
|
||||||
|
| user | UUID | 用户 ID |
|
||||||
|
| role | ENUM | `Owner` / `Admin` / `Member` |
|
||||||
|
| first_msg_in | TIMESTAMPTZ (nullable) | 首次发消息时间 |
|
||||||
|
| joined_at | TIMESTAMPTZ (nullable) | 加入时间 |
|
||||||
|
| last_read_seq | BIGINT (nullable) | 已读序列号 |
|
||||||
|
| do_not_disturb | BOOLEAN | 免打扰 |
|
||||||
|
| dnd_start_hour | INT (nullable) | DND 开始小时 |
|
||||||
|
| dnd_end_hour | INT (nullable) | DND 结束小时 |
|
||||||
|
|
||||||
|
#### `room_category` - 频道分类表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | UUID | 主键 |
|
||||||
|
| project | UUID | 所属项目 |
|
||||||
|
| name | VARCHAR(64) | 分类名称 |
|
||||||
|
| position | INT | 排序位置 |
|
||||||
|
|
||||||
|
#### `room_thread` - 线程表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | UUID | 主键 |
|
||||||
|
| room | UUID | 所属房间 |
|
||||||
|
| parent_message | UUID | 父消息 ID |
|
||||||
|
| created_by | UUID | 创建者 |
|
||||||
|
| created_at | TIMESTAMPTZ | 创建时间 |
|
||||||
|
|
||||||
|
#### `room_ai` - AI 配置表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| room | UUID | 房间 ID |
|
||||||
|
| model | UUID | AI 模型 ID |
|
||||||
|
| version | VARCHAR (nullable) | 模型版本 |
|
||||||
|
| call_count | INT | 调用次数 |
|
||||||
|
| last_call_at | TIMESTAMPTZ (nullable) | 最后调用时间 |
|
||||||
|
| history_limit | INT | 上下文历史限制 |
|
||||||
|
| system_prompt | TEXT | 系统提示词 |
|
||||||
|
| temperature | FLOAT | 温度参数 |
|
||||||
|
| max_tokens | INT | 最大 token 数 |
|
||||||
|
| use_exact | BOOLEAN | 精确模式 |
|
||||||
|
| think | BOOLEAN | 思考模式 |
|
||||||
|
| stream | BOOLEAN | 流式输出 |
|
||||||
|
| min_score | FLOAT (nullable) | 最小分数阈值 |
|
||||||
|
|
||||||
|
#### `room_message_reaction` - 消息反应表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | UUID | 主键 |
|
||||||
|
| message | UUID | 消息 ID |
|
||||||
|
| user | UUID | 用户 ID |
|
||||||
|
| emoji | VARCHAR(32) | emoji |
|
||||||
|
| created_at | TIMESTAMPTZ | 创建时间 |
|
||||||
|
|
||||||
|
#### `room_pin` - 置顶消息表
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | UUID | 主键 |
|
||||||
|
| room | UUID | 房间 ID |
|
||||||
|
| message | UUID | 消息 ID |
|
||||||
|
| pinned_by | UUID | 置顶者 |
|
||||||
|
| pinned_at | TIMESTAMPTZ | 置顶时间 |
|
||||||
|
|
||||||
|
### 2.2 消息内容类型
|
||||||
|
```typescript
|
||||||
|
type MessageContentType = 'text' | 'markdown' | 'code' | 'mention';
|
||||||
|
|
||||||
|
type MessageSenderType = 'member' | 'ai' | 'system';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. WebSocket 通信协议
|
||||||
|
|
||||||
|
### 3.1 协议格式
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
```typescript
|
||||||
|
interface WsRequest {
|
||||||
|
type: 'request';
|
||||||
|
request_id: string; // 唯一请求 ID
|
||||||
|
action: WsAction; // 操作类型
|
||||||
|
params?: WsRequestParams;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
```typescript
|
||||||
|
interface WsResponse {
|
||||||
|
type: 'response';
|
||||||
|
request_id: string;
|
||||||
|
action: string;
|
||||||
|
data?: WsResponseData;
|
||||||
|
error?: WsError;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Action 列表
|
||||||
|
|
||||||
|
#### 房间管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `room.list` | 获取房间列表 | Member |
|
||||||
|
| `room.get` | 获取房间详情 | Member |
|
||||||
|
| `room.create` | 创建房间 | Admin |
|
||||||
|
| `room.update` | 更新房间 | Admin |
|
||||||
|
| `room.delete` | 删除房间 | Admin |
|
||||||
|
| `room.subscribe` | 订阅房间事件 | Member |
|
||||||
|
| `room.unsubscribe` | 取消订阅 | Member |
|
||||||
|
|
||||||
|
#### 消息管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `message.list` | 获取消息列表(分页) | Member |
|
||||||
|
| `message.create` | 发送消息 | Member |
|
||||||
|
| `message.update` | 编辑消息 | Owner |
|
||||||
|
| `message.revoke` | 撤回消息 | Owner |
|
||||||
|
| `message.get` | 获取单条消息 | Member |
|
||||||
|
| `message.search` | 搜索消息 | Member |
|
||||||
|
|
||||||
|
#### 成员管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `member.list` | 获取成员列表 | Member |
|
||||||
|
| `member.add` | 添加成员 | Admin |
|
||||||
|
| `member.remove` | 移除成员 | Admin |
|
||||||
|
| `member.leave` | 离开房间 | Member |
|
||||||
|
| `member.update_role` | 更新角色 | Admin |
|
||||||
|
| `member.set_read_seq` | 设置已读位置 | Member |
|
||||||
|
|
||||||
|
#### 分类管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `category.list` | 获取分类列表 | Member |
|
||||||
|
| `category.create` | 创建分类 | Admin |
|
||||||
|
| `category.update` | 更新分类 | Admin |
|
||||||
|
| `category.delete` | 删除分类 | Admin |
|
||||||
|
|
||||||
|
#### 线程管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `thread.list` | 获取线程列表 | Member |
|
||||||
|
| `thread.create` | 创建线程 | Member |
|
||||||
|
| `thread.messages` | 获取线程消息 | Member |
|
||||||
|
|
||||||
|
#### 反应管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `reaction.add` | 添加反应 | Member |
|
||||||
|
| `reaction.remove` | 移除反应 | Owner |
|
||||||
|
| `reaction.list_batch` | 批量获取反应 | Member |
|
||||||
|
|
||||||
|
#### 置顶管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `pin.list` | 获取置顶列表 | Member |
|
||||||
|
| `pin.add` | 添加置顶 | Admin |
|
||||||
|
| `pin.remove` | 移除置顶 | Admin |
|
||||||
|
|
||||||
|
#### AI 管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `ai.list` | 获取 AI 配置列表 | Member |
|
||||||
|
| `ai.upsert` | 创建/更新 AI 配置 | Admin |
|
||||||
|
| `ai.delete` | 删除 AI 配置 | Admin |
|
||||||
|
|
||||||
|
#### 通知管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `notification.list` | 获取通知列表 | Member |
|
||||||
|
| `notification.mark_read` | 标记已读 | Member |
|
||||||
|
| `notification.mark_all_read` | 全部标记已读 | Member |
|
||||||
|
| `notification.archive` | 归档通知 | Member |
|
||||||
|
|
||||||
|
#### 提及管理
|
||||||
|
| Action | 说明 | 权限 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `mention.list` | 获取提及列表 | Member |
|
||||||
|
| `mention.read_all` | 全部标记已读 | Member |
|
||||||
|
|
||||||
|
### 3.3 实时事件推送
|
||||||
|
```typescript
|
||||||
|
type WsEventType =
|
||||||
|
| 'room.created'
|
||||||
|
| 'room.updated'
|
||||||
|
| 'room.deleted'
|
||||||
|
| 'message.created'
|
||||||
|
| 'message.updated'
|
||||||
|
| 'message.revoked'
|
||||||
|
| 'member.joined'
|
||||||
|
| 'member.left'
|
||||||
|
| 'member.role_changed'
|
||||||
|
| 'thread.created'
|
||||||
|
| 'reaction.updated'
|
||||||
|
| 'pin.updated';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 后端架构
|
||||||
|
|
||||||
|
### 4.1 目录结构
|
||||||
|
```
|
||||||
|
libs/room/src/
|
||||||
|
├── lib.rs # 模块入口
|
||||||
|
├── service.rs # RoomService 主服务
|
||||||
|
├── room.rs # 房间 CRUD
|
||||||
|
├── message.rs # 消息管理
|
||||||
|
├── member.rs # 成员管理
|
||||||
|
├── category.rs # 分类管理
|
||||||
|
├── thread.rs # 线程管理
|
||||||
|
├── reaction.rs # 反应管理
|
||||||
|
├── pin.rs # 置顶管理
|
||||||
|
├── ai.rs # AI 配置管理
|
||||||
|
├── notification.rs # 通知管理
|
||||||
|
├── search.rs # 搜索功能
|
||||||
|
├── connection.rs # WebSocket 连接管理
|
||||||
|
├── room_ai_queue.rs # AI 队列锁
|
||||||
|
├── error.rs # 错误类型
|
||||||
|
├── types.rs # 请求/响应类型
|
||||||
|
├── helpers.rs # 辅助函数
|
||||||
|
├── metrics.rs # 指标收集
|
||||||
|
├── ws_context.rs # WebSocket 上下文
|
||||||
|
└── draft_and_history.rs # 草稿和编辑历史
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 核心服务 RoomService
|
||||||
|
```rust
|
||||||
|
pub struct RoomService {
|
||||||
|
db: DatabaseConnection,
|
||||||
|
cache: AppCache,
|
||||||
|
queue: NatsContext,
|
||||||
|
ai_client: AiClient,
|
||||||
|
rate_limiter: RateLimiter,
|
||||||
|
log: Logger,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 并发控制
|
||||||
|
- **物理并发限制**: `tokio::sync::Semaphore`
|
||||||
|
- **消息序列号**: Redis INCR 原子递增
|
||||||
|
- **消息去重**: `DashMap<UUID, HashSet<i64>>` 内存缓存
|
||||||
|
- **AI 队列锁**: Redis 分布式锁 (`ai:room:queue:lock:{room_id}`)
|
||||||
|
|
||||||
|
### 4.4 AI 队列机制
|
||||||
|
```rust
|
||||||
|
// Redis 键结构
|
||||||
|
ai:room:queue:{room_id} // 队列
|
||||||
|
ai:room:queue:seq:{room_id} // 序号
|
||||||
|
ai:room:queue:lock:{room_id} // 分布式锁
|
||||||
|
ai:room:queue:ticket:{room_id}:{ticket_id} // 票据
|
||||||
|
|
||||||
|
// 锁参数
|
||||||
|
LOCK_TTL_MS: 120_000 // 锁超时 2 分钟
|
||||||
|
TICKET_TTL_MS: 90_000 // 票据超时 1.5 分钟
|
||||||
|
MAX_BACKOFF_MS: 200 // 最大退避 200ms
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.5 定时任务
|
||||||
|
- **空闲房间清理**: 30 天无消息的房间标记为归档
|
||||||
|
- **频率限制刷新**: 每分钟重置计数
|
||||||
|
- **陈旧指标清理**: 定期清理过期数据
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 前端架构
|
||||||
|
|
||||||
|
### 5.1 目录结构
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── components/room/
|
||||||
|
│ ├── DiscordServerSidebar.tsx # 服务器图标侧边栏 (72px)
|
||||||
|
│ ├── DiscordChannelSidebar.tsx # 可折叠频道列表
|
||||||
|
│ ├── DiscordChatPanel.tsx # 主聊天面板
|
||||||
|
│ ├── DiscordMemberList.tsx # 成员列表 (带在线状态)
|
||||||
|
│ ├── message/
|
||||||
|
│ │ ├── MessageList.tsx # 消息列表
|
||||||
|
│ │ ├── MessageInput.tsx # 消息输入框
|
||||||
|
│ │ ├── MessageBubble.tsx # 消息气泡
|
||||||
|
│ │ └── MessageActions.tsx # 消息操作菜单
|
||||||
|
│ ├── RoomThreadPanel.tsx # 线程侧边栏
|
||||||
|
│ ├── RoomMentionPanel.tsx # 提及面板
|
||||||
|
│ ├── RoomPinBar.tsx # 置顶栏
|
||||||
|
│ ├── RoomMessageSearch.tsx # 消息搜索
|
||||||
|
│ ├── RoomSettingsPanel.tsx # 设置面板
|
||||||
|
│ ├── RoomAiAuthBanner.tsx # AI 认证提示
|
||||||
|
│ ├── RoomAiTasksPanel.tsx # AI 任务面板
|
||||||
|
│ └── ...
|
||||||
|
├── contexts/
|
||||||
|
│ └── room-context.tsx # 房间状态管理
|
||||||
|
└── lib/
|
||||||
|
└── ws-protocol.ts # WebSocket 协议定义
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 React Context 状态管理
|
||||||
|
```typescript
|
||||||
|
interface RoomContextValue {
|
||||||
|
// 房间状态
|
||||||
|
rooms: RoomResponse[];
|
||||||
|
currentRoom: RoomResponse | null;
|
||||||
|
roomsLoading: boolean;
|
||||||
|
|
||||||
|
// 消息状态
|
||||||
|
messages: MessageWithMeta[];
|
||||||
|
threads: RoomThreadResponse[];
|
||||||
|
|
||||||
|
// 成员状态
|
||||||
|
members: RoomMember[];
|
||||||
|
membersLoading: boolean;
|
||||||
|
|
||||||
|
// AI 配置
|
||||||
|
roomAiConfigs: RoomAiResponse[];
|
||||||
|
|
||||||
|
// WebSocket 状态
|
||||||
|
wsStatus: 'open' | 'connecting' | 'disconnected';
|
||||||
|
wsError: Error | null;
|
||||||
|
wsClient: WebSocketClient | null;
|
||||||
|
|
||||||
|
// 操作方法
|
||||||
|
sendMessage: (content: string, inReplyTo?: string) => Promise<void>;
|
||||||
|
editMessage: (messageId: string, content: string) => Promise<void>;
|
||||||
|
revokeMessage: (messageId: string) => Promise<void>;
|
||||||
|
updateRoom: (roomId: string, data: Partial<RoomUpdateRequest>) => Promise<void>;
|
||||||
|
refreshThreads: () => Promise<void>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 Discord 风格 UI 布局
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ [Icon] │ # channel-name [🔍][👤] │
|
||||||
|
├──────────┼─────────────────────────────────────────┬────────────┤
|
||||||
|
│ │ ┌─────────────────────────────────┐ │ │
|
||||||
|
│ Category │ │ Message List │ │ Members │
|
||||||
|
│ ────────│ │ (with virtual scrolling) │ │ Online(3) │
|
||||||
|
│ # gen │ │ │ │ ● user1 │
|
||||||
|
│ # dev │ │ user1 [10:30] Hello! │ │ ● user2 │
|
||||||
|
│ # ai │ │ ↳ user2 [10:32] Hi! │ │ │
|
||||||
|
│ │ │ │ │ Offline(5)│
|
||||||
|
│ Category │ │ 🤖 AI [10:33] Thinking... │ │ ○ user3 │
|
||||||
|
│ ────────│ │ │ │ │
|
||||||
|
│ 🔒 priv │ └─────────────────────────────────┘ │ │
|
||||||
|
│ ├─────────────────────────────────────────┤ │
|
||||||
|
│ │ [+] Type a message... [@][📎] │ │
|
||||||
|
└──────────┴─────────────────────────────────────────┴────────────┘
|
||||||
|
72px Flex: 1 240px
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4 消息数据流
|
||||||
|
```
|
||||||
|
用户输入 → MessageInput
|
||||||
|
↓
|
||||||
|
WebSocket.send({ action: 'message.create', params: { content, room_id } })
|
||||||
|
↓
|
||||||
|
后端处理 → Redis INCR seq → DB insert → NATS publish
|
||||||
|
↓
|
||||||
|
WebSocket.push({ event: 'message.created', data: message })
|
||||||
|
↓
|
||||||
|
RoomContext.handleMessage() → setMessages(prev => [...prev, message])
|
||||||
|
↓
|
||||||
|
MessageList 渲染
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. API 端点 (REST)
|
||||||
|
|
||||||
|
### 6.1 房间管理
|
||||||
|
```
|
||||||
|
GET /api/projects/{project}/rooms # 房间列表
|
||||||
|
GET /api/projects/{project}/rooms/{room} # 房间详情
|
||||||
|
POST /api/projects/{project}/rooms # 创建房间
|
||||||
|
PATCH /api/projects/{project}/rooms/{room} # 更新房间
|
||||||
|
DELETE /api/projects/{project}/rooms/{room} # 删除房间
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 消息管理
|
||||||
|
```
|
||||||
|
GET /api/rooms/{room}/messages # 消息列表 (分页)
|
||||||
|
GET /api/rooms/{room}/messages/{message} # 单条消息
|
||||||
|
POST /api/rooms/{room}/messages # 发送消息
|
||||||
|
PATCH /api/rooms/{room}/messages/{message} # 编辑消息
|
||||||
|
DELETE /api/rooms/{room}/messages/{message} # 撤回消息
|
||||||
|
GET /api/rooms/{room}/messages/search # 搜索消息
|
||||||
|
GET /api/rooms/{room}/messages/{message}/history # 编辑历史
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 AI 端点
|
||||||
|
```
|
||||||
|
GET /api/rooms/{room}/ai # AI 配置列表
|
||||||
|
POST /api/rooms/{room}/ai # 创建 AI 配置
|
||||||
|
PATCH /api/rooms/{room}/ai/{model} # 更新 AI 配置
|
||||||
|
DELETE /api/rooms/{room}/ai/{model} # 删除 AI 配置
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 关键设计原则
|
||||||
|
|
||||||
|
| 原则 | 实现方式 |
|
||||||
|
|------|----------|
|
||||||
|
| 高内聚低耦合 | 模块化服务层、清晰的领域边界 |
|
||||||
|
| 异步非阻塞 | Tokio async/await、Redis 异步客户端 |
|
||||||
|
| 事件驱动 | NATS Pub/Sub 解耦组件 |
|
||||||
|
| 强类型安全 | TypeScript + Rust 编译期检查 |
|
||||||
|
| 分层架构 | Service → Repository → Database |
|
||||||
|
| 鲁棒性优先 | 完善的错误处理、限流、资源回收 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 已实现功能清单
|
||||||
|
|
||||||
|
### 8.1 核心功能 ✅
|
||||||
|
- [x] 房间 CRUD (创建/读取/更新/删除)
|
||||||
|
- [x] 消息 CRUD (发送/编辑/撤回/历史)
|
||||||
|
- [x] 成员管理 (邀请/移除/角色变更)
|
||||||
|
- [x] 频道分类 (创建/排序/折叠)
|
||||||
|
- [x] 线程回复 (创建线程/线程消息)
|
||||||
|
- [x] 消息反应 (emoji 反应)
|
||||||
|
- [x] 消息置顶
|
||||||
|
- [x] 消息搜索
|
||||||
|
- [x] 未读计数
|
||||||
|
|
||||||
|
### 8.2 实时功能 ✅
|
||||||
|
- [x] WebSocket 长连接
|
||||||
|
- [x] 消息实时推送
|
||||||
|
- [x] 成员状态同步
|
||||||
|
- [x] 在线状态显示
|
||||||
|
- [x] 消息去重
|
||||||
|
- [x] IndexedDB 离线缓存
|
||||||
|
- [x] 虚拟滚动列表 (@tanstack/react-virtual)
|
||||||
|
|
||||||
|
### 8.3 AI 集成 ✅
|
||||||
|
- [x] AI 模型配置
|
||||||
|
- [x] AI 消息发送
|
||||||
|
- [x] 系统提示词
|
||||||
|
- [x] 上下文历史限制
|
||||||
|
- [x] 流式输出支持
|
||||||
|
- [x] AI 队列锁
|
||||||
|
|
||||||
|
### 8.4 富媒体消息 ✅
|
||||||
|
- [x] 消息内容类型: text, image, audio, video, file
|
||||||
|
- [x] Tiptap 富文本编辑器 (IMEditor)
|
||||||
|
- [x] FileNode Tiptap 扩展 (文件/图片节点)
|
||||||
|
- [x] 文件上传状态管理 (uploading/done/error)
|
||||||
|
- [x] Markdown 支持
|
||||||
|
|
||||||
|
### 8.5 全文搜索 ✅
|
||||||
|
- [x] PostgreSQL 全文索引 (GIN + tsvector)
|
||||||
|
- [x] 搜索 API (room_message_search)
|
||||||
|
- [x] 分页与结果计数
|
||||||
|
|
||||||
|
### 8.6 通知系统 ✅
|
||||||
|
- [x] 提及通知
|
||||||
|
- [x] 线程通知
|
||||||
|
- [x] DND 免打扰时段 (do_not_disturb, dnd_start/end_hour)
|
||||||
|
|
||||||
|
### 8.4 用户体验 ✅
|
||||||
|
- [x] 消息草稿自动保存
|
||||||
|
- [x] @提及功能
|
||||||
|
- [x] 回复引用
|
||||||
|
- [x] 消息时间格式化
|
||||||
|
- [x] Discord 风格 UI
|
||||||
|
- [x] 侧边栏折叠
|
||||||
|
- [x] 成员列表按角色着色
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 已完成功能 (详细技术方案)
|
||||||
|
|
||||||
|
### 9.1 富媒体消息支持 ✅
|
||||||
|
|
||||||
|
#### 9.1.1 图片消息
|
||||||
|
```
|
||||||
|
技术实现:
|
||||||
|
- 前端: FileNode.tsx Tiptap 扩展,支持 inline 文件节点
|
||||||
|
- 富媒体消息类型: MessageContentType::Image, Audio, Video, File
|
||||||
|
- 文件上传: Tiptap IMEditor 支持拖拽上传
|
||||||
|
- 状态管理: uploading/done/error 三种状态
|
||||||
|
|
||||||
|
代码位置:
|
||||||
|
- src/components/room/message/editor/FileNode.tsx (Tiptap 文件节点)
|
||||||
|
- src/components/room/message/editor/IMEditor.tsx (富文本编辑器)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 9.1.2 消息内容类型 ✅
|
||||||
|
```
|
||||||
|
已实现的消息类型:
|
||||||
|
- Text (text)
|
||||||
|
- Image (image)
|
||||||
|
- Audio (audio)
|
||||||
|
- Video (video)
|
||||||
|
- File (file)
|
||||||
|
|
||||||
|
代码位置:
|
||||||
|
- libs/models/rooms/mod.rs (MessageContentType enum)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 历史消息优化 ✅
|
||||||
|
|
||||||
|
#### 9.2.1 虚拟滚动列表
|
||||||
|
```
|
||||||
|
技术实现:
|
||||||
|
- @tanstack/react-virtual + useVirtualizer
|
||||||
|
- 按需渲染可见区域消息 (overscan: 30)
|
||||||
|
- 动态高度估算 (estimateMessageRowHeight)
|
||||||
|
- 日期分隔符自动插入
|
||||||
|
- 滚动位置保持 (加载更多时)
|
||||||
|
|
||||||
|
代码位置:
|
||||||
|
- src/components/room/message/MessageList.tsx
|
||||||
|
|
||||||
|
功能特性:
|
||||||
|
- [x] IntersectionObserver 自动加载更多
|
||||||
|
- [x] 滚动位置恢复
|
||||||
|
- [x] 滚动到底部按钮
|
||||||
|
- [x] 日期分组分隔符
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 9.2.2 IndexedDB 离线缓存 ✅
|
||||||
|
```
|
||||||
|
技术实现:
|
||||||
|
- IndexedDB 本地持久化存储
|
||||||
|
- 双索引: by_room, by_room_seq
|
||||||
|
- 支持离线消息恢复
|
||||||
|
- 自动保存/加载消息
|
||||||
|
|
||||||
|
API:
|
||||||
|
- saveMessage(msg) # 保存单条
|
||||||
|
- saveMessages(roomId, msgs) # 批量保存
|
||||||
|
- loadMessages(roomId) # 加载房间消息
|
||||||
|
- loadOlderMessagesFromIdb() # 加载历史消息
|
||||||
|
- getMaxSeq(roomId) # 获取最大序列号 (去重)
|
||||||
|
|
||||||
|
代码位置:
|
||||||
|
- src/lib/storage/indexed-db.ts
|
||||||
|
- src/contexts/room-context.tsx (集成缓存)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.3 全文搜索 ✅
|
||||||
|
|
||||||
|
#### 9.3.1 PostgreSQL 全文索引
|
||||||
|
```
|
||||||
|
技术实现:
|
||||||
|
- content_tsv TSVECTOR 列
|
||||||
|
- GIN 索引 (idx_room_message_content_tsv)
|
||||||
|
- plainto_tsquery('simple', query) 全文搜索
|
||||||
|
|
||||||
|
代码位置:
|
||||||
|
- libs/room/src/search.rs (room_message_search)
|
||||||
|
- libs/migrate/sql/m20250628_000080_add_message_reactions_and_search.sql
|
||||||
|
|
||||||
|
搜索功能:
|
||||||
|
- [x] 全文搜索 API
|
||||||
|
- [x] 分页支持 (limit, offset)
|
||||||
|
- [x] 结果计数 (total)
|
||||||
|
- [x] 显示名称解析
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.4 通知系统完善 ✅
|
||||||
|
|
||||||
|
#### 9.4.1 多维度通知配置 ✅
|
||||||
|
```
|
||||||
|
技术实现:
|
||||||
|
- room_member 表新增字段:
|
||||||
|
- do_not_disturb: BOOLEAN (免打扰开关)
|
||||||
|
- dnd_start_hour: INT (DND 开始时间, 0-23)
|
||||||
|
- dnd_end_hour: INT (DND 结束时间, 0-23)
|
||||||
|
|
||||||
|
数据库迁移:
|
||||||
|
- libs/migrate/m20250628_000078_add_room_member_do_not_disturb.rs
|
||||||
|
|
||||||
|
代码位置:
|
||||||
|
- libs/models/rooms/room_member.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 9.4.2 通知系统
|
||||||
|
```
|
||||||
|
已实现功能:
|
||||||
|
- [x] 提及通知 (Mention)
|
||||||
|
- [x] 线程通知 (Thread)
|
||||||
|
- [x] DND 免打扰时段
|
||||||
|
- [x] 通知列表 API
|
||||||
|
- [x] 标记已读 API
|
||||||
|
|
||||||
|
代码位置:
|
||||||
|
- libs/room/src/notification.rs
|
||||||
|
- libs/service/user/notification.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 待实现功能
|
||||||
|
|
||||||
|
### 10.1 富媒体消息完善
|
||||||
|
|
||||||
|
```
|
||||||
|
待实现:
|
||||||
|
1. [ ] 对象存储集成 (S3/MinIO)
|
||||||
|
2. [ ] 文件下载 API
|
||||||
|
3. [ ] 图片预览 Modal
|
||||||
|
4. [ ] 视频播放器集成
|
||||||
|
5. [ ] Office 文档预览
|
||||||
|
6. [ ] 文件大小/类型验证
|
||||||
|
7. [ ] 图片压缩 (WebWorker)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.2 全文搜索增强
|
||||||
|
|
||||||
|
```
|
||||||
|
待实现:
|
||||||
|
1. [ ] 时间范围筛选
|
||||||
|
2. [ ] 用户筛选 (@username)
|
||||||
|
3. [ ] 文件类型筛选 (content_type)
|
||||||
|
4. [ ] 搜索历史记录
|
||||||
|
5. [ ] 结果高亮
|
||||||
|
6. [ ] 正则搜索支持
|
||||||
|
7. [ ] 数据库触发器自动更新 tsvector
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.3 推送通知
|
||||||
|
|
||||||
|
```
|
||||||
|
待实现:
|
||||||
|
1. [ ] Web Push 集成 (service worker)
|
||||||
|
2. [ ] 移动端推送
|
||||||
|
3. [ ] 通知中心 UI
|
||||||
|
4. [ ] 未读计数 Badge
|
||||||
|
5. [ ] 关键词提醒
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.4 性能优化
|
||||||
|
|
||||||
|
```
|
||||||
|
待实现:
|
||||||
|
1. [ ] room_message 表分区 (按时间)
|
||||||
|
2. [ ] 读写分离
|
||||||
|
3. [ ] 房间列表缓存 (Redis)
|
||||||
|
4. [ ] 成员列表缓存
|
||||||
|
5. [ ] Redis Pipeline 批量操作
|
||||||
|
6. [ ] 组件代码分割 (React.lazy)
|
||||||
|
7. [ ] 图片懒加载
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.5 AI 增强功能
|
||||||
|
|
||||||
|
```
|
||||||
|
待实现:
|
||||||
|
1. [ ] AI 连续对话上下文管理
|
||||||
|
2. [ ] AI 会话历史管理
|
||||||
|
3. [ ] AI 切换对话线程
|
||||||
|
4. [ ] AI 输出 Markdown 渲染优化
|
||||||
|
5. [ ] AI 工具调用扩展 (消息引用/代码执行/搜索)
|
||||||
|
6. [ ] 定时 AI 任务
|
||||||
|
7. [ ] 会议纪要生成
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.6 国际化 (i18n)
|
||||||
|
|
||||||
|
```
|
||||||
|
待实现:
|
||||||
|
1. [ ] 前端 i18n (react-i18next)
|
||||||
|
2. [ ] 后端 i18n (rust-i18n)
|
||||||
|
3. [ ] 提取 UI 字符串
|
||||||
|
4. [ ] 语言切换器
|
||||||
|
5. [ ] 日期/时间本地化
|
||||||
|
6. [ ] RTL 语言支持
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 测试计划
|
||||||
|
|
||||||
|
### 11.1 单元测试
|
||||||
|
- [ ] RoomService 业务逻辑测试
|
||||||
|
- [ ] 消息序列号生成测试
|
||||||
|
- [ ] 权限检查测试
|
||||||
|
- [ ] React Hooks 测试
|
||||||
|
|
||||||
|
### 11.2 集成测试
|
||||||
|
- [ ] WebSocket 连接测试
|
||||||
|
- [ ] 数据库事务测试
|
||||||
|
- [ ] Redis 缓存测试
|
||||||
|
- [ ] NATS 消息分发测试
|
||||||
|
|
||||||
|
### 11.3 E2E 测试
|
||||||
|
- [ ] 房间创建流程
|
||||||
|
- [ ] 消息发送与接收
|
||||||
|
- [ ] 消息编辑与撤回
|
||||||
|
- [ ] AI 对话流程
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 部署与运维
|
||||||
|
|
||||||
|
### 11.1 环境变量
|
||||||
|
```
|
||||||
|
# 数据库
|
||||||
|
DATABASE_URL=postgresql://user:pass@host:5432/db
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_URL=redis://host:6379
|
||||||
|
|
||||||
|
# NATS
|
||||||
|
NATS_URL=nats://host:4222
|
||||||
|
|
||||||
|
# 对象存储
|
||||||
|
S3_ENDPOINT=https://s3.example.com
|
||||||
|
S3_BUCKET=room-media
|
||||||
|
AWS_ACCESS_KEY_ID=xxx
|
||||||
|
AWS_SECRET_ACCESS_KEY=xxx
|
||||||
|
|
||||||
|
# AI
|
||||||
|
OPENAI_API_KEY=sk-xxx
|
||||||
|
OPENROUTER_API_KEY=xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.2 Kubernetes 配置
|
||||||
|
```
|
||||||
|
# Room Service Deployment
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
|
||||||
|
# HPA 自动扩缩容
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: 70
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.3 监控指标
|
||||||
|
- WebSocket 连接数
|
||||||
|
- 消息吞吐量 (msg/s)
|
||||||
|
- AI 调用延迟
|
||||||
|
- Redis 缓存命中率
|
||||||
|
- 数据库查询延迟
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. 安全考虑
|
||||||
|
|
||||||
|
### 12.1 权限模型
|
||||||
|
```
|
||||||
|
项目权限 → 房间权限 → 成员角色
|
||||||
|
Admin/Owner → Admin/Owner/Member
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12.2 输入验证
|
||||||
|
- 消息内容长度限制 (MAX: 10000 chars)
|
||||||
|
- 文件大小限制 (MAX: 100MB)
|
||||||
|
- 文件类型白名单
|
||||||
|
|
||||||
|
### 12.3 CSRF/XSS 防护
|
||||||
|
- WebSocket 请求携带 JWT
|
||||||
|
- 消息内容转义
|
||||||
|
- 文件名 sanitize
|
||||||
Loading…
Reference in New Issue
Block a user