diff --git a/docs/api/README.md b/docs/api/README.md index ab1b292..41abcc0 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -17,7 +17,7 @@ | [frontend/websocket.md](frontend/websocket.md) | WebSocket | ✅ Phase 2a | 前端 WebSocket 连接管理、事件协议、心跳、重连 | | [frontend/im.md](frontend/im.md) | 即时通讯 | ✅ Phase 2b | 7 个 API:会话列表/置顶/删除/清空、历史消息、全局搜索、未读数 | | [frontend/group.md](frontend/group.md) | 群聊管理 | ✅ Phase 2c | 16 个 API:建群/管理/成员/角色/禁言/公告/搜索/入群审批 | -| [frontend/meeting.md](frontend/meeting.md) | 会议 | 📋 Phase 2e-2 设计阶段 | 当前为总设计占位版本;最终 API 清单将由 Phase 2e-2 Task 5 产出(共 12 接口,含创建/加入/离开/结束/详情/列表/邀请/踢人/转让主持人/发起聊天/拉聊天历史/邀请链接兑换)。详见设计文档 `docs/plans/2026-04-21-phase2e-2-design.md` §6.2 | +| [frontend/meeting.md](frontend/meeting.md) | 会议 | ✅ Phase 2e-2 Task 5/6 | 12 个 REST 接口(创建/加入/离开/结束/详情/列表/邀请/踢人/转让主持人/发起聊天/拉聊天历史/邀请链接兑换)+ 13 个 WebSocket 信令事件(8 C→S + 5 核心 S→C 广播 + 会议内聊天/被踢定向推送),Redis 媒体资源追踪 + host 权限校验 | | [frontend/notify.md](frontend/notify.md) | 通知中心 | ✅ Phase 2e-1 | 5 个 API:通知列表(游标分页)/未读数/标记已读/全部已读/管理员广播 + 2 个 WS 事件(notify.new/notify.unread.total) | ### 后台管理端 (`admin/`) @@ -199,8 +199,8 @@ docs/api/ │ ├── websocket.md # WebSocket 事件协议 ✅ Phase 2a │ ├── im.md # 即时通讯(8 个 API) ✅ Phase 2b/2c │ ├── group.md # 群聊管理(16 个 API) ✅ Phase 2c -│ ├── meeting.md # 会议 📋 后续 -│ └── notify.md # 通知 📋 后续 +│ ├── meeting.md # 会议(12 REST + 13 WS 事件) ✅ Phase 2e-2 (Task 5/6) +│ └── notify.md # 通知(5 API + 2 WS 事件) ✅ Phase 2e-1 ├── admin/ # 后台管理端 API │ ├── auth.md # 管理员认证 ✅ Phase 1 │ ├── user.md # 用户管理 ✅ Phase 1 diff --git a/docs/api/websocket.md b/docs/api/websocket.md index ad7c75d..2b60430 100644 --- a/docs/api/websocket.md +++ b/docs/api/websocket.md @@ -203,167 +203,35 @@ --- -## 会议信令事件 - -### meeting.room.join - -**方向:** 客户端 → 服务端 - -**说明:** 加入会议房间 - -**data 参数:** `{ "room_code": "123-456-789" }` - -**ACK 响应 data:** 房间信息、参与者列表、RTP Capabilities - ---- - -### meeting.room.leave - -**方向:** 客户端 → 服务端 - -**说明:** 离开会议房间 - -**data 参数:** `{ "room_code": "123-456-789" }` - ---- - -### meeting.room.info - -**方向:** 服务端 → 客户端 - -**说明:** 房间信息同步(成员变更、设置变更时推送) - ---- - -### meeting.member.join - -**方向:** 服务端 → 客户端(广播) - -**说明:** 有新成员加入会议 - -**data 内容:** -```json -{ - "room_code": "123-456-789", - "user_id": 3, - "nickname": "王五", - "avatar": "https://...", - "role": 0 -} -``` - ---- - -### meeting.member.leave - -**方向:** 服务端 → 客户端(广播) - -**说明:** 有成员离开会议 - -**data 内容:** `{ "room_code": "...", "user_id": 3 }` - ---- - -### meeting.member.mute - -**方向:** 双向 - -**说明:** 静音/解除静音 - -**data 内容:** `{ "room_code": "...", "user_id": 1, "muted": true }` - ---- - -### meeting.member.video - -**方向:** 双向 - -**说明:** 开关摄像头 - -**data 内容:** `{ "room_code": "...", "user_id": 1, "video_enabled": false }` - ---- - -## mediasoup 信令事件 - -### meeting.transport.create - -**方向:** 客户端 → 服务端 - -**说明:** 请求创建 WebRTC Transport(发送端或接收端) - -**data 参数:** `{ "room_code": "...", "direction": "send" }` 或 `"recv"` - -**ACK 响应 data:** Transport 参数(id, iceParameters, iceCandidates, dtlsParameters) - ---- - -### meeting.transport.connect - -**方向:** 客户端 → 服务端 - -**说明:** 完成 Transport DTLS 握手 - -**data 参数:** `{ "transport_id": "...", "dtls_parameters": { ... } }` - ---- - -### meeting.produce.start - -**方向:** 客户端 → 服务端 - -**说明:** 开始推流(音频或视频) - -**data 参数:** -```json -{ - "transport_id": "...", - "kind": "video", - "rtp_parameters": { ... } -} -``` - -**ACK 响应 data:** `{ "producer_id": "..." }` - ---- - -### meeting.produce.stop - -**方向:** 客户端 → 服务端 - -**说明:** 停止推流 - -**data 参数:** `{ "producer_id": "..." }` - ---- - -### meeting.consume.start - -**方向:** 服务端 → 客户端 - -**说明:** 通知客户端可以开始接收某个参与者的流 - -**data 内容:** -```json -{ - "consumer_id": "...", - "producer_id": "...", - "kind": "video", - "rtp_parameters": { ... }, - "user_id": 3, - "nickname": "王五" -} -``` - ---- - -### meeting.consume.resume - -**方向:** 客户端 → 服务端 - -**说明:** 恢复被暂停的 Consumer - -**data 参数:** `{ "consumer_id": "..." }` +## 会议信令事件(Phase 2e-2 Task 6 已落地) + +> **SSOT**:会议相关的全部 WS 事件详细契约(请求/ACK/广播载荷、权限、错误处理、资源追踪)见 [`docs/api/frontend/meeting.md`](./frontend/meeting.md) §WebSocket 信令协议。本节仅列事件总览。 + +| # | 方向 | 事件 | 用途 | +|---|------|------|------| +| 1 | C→S | `meeting.room.join` | 声明加入某会议 WS 频道(需已在 REST 层完成 `/join`)| +| 2 | C→S | `meeting.room.leave` | 离开 WS 频道并清理媒体资源(不改 participant 表)| +| 3 | C→S | `meeting.member.state.changed` | 更新自己的 audio/video/hand_raised;host 可指定 `target_user_id` 强制静音他人 | +| 4 | C→S | `meeting.transport.create` | 创建 mediasoup WebRtcTransport(`direction: send/recv`)| +| 5 | C→S | `meeting.transport.connect` | 提交 DTLS Parameters | +| 6 | C→S | `meeting.produce.start` | 创建 Producer | +| 7 | C→S | `meeting.consume.start` | 创建 Consumer | +| 8 | C→S | `meeting.producer.close` | 关闭自己的 Producer | +| 9 | S→C | `meeting.member.joined` | 新成员加入广播(REST /join 触发)| +| 10 | S→C | `meeting.member.left` | 成员离开广播(REST /leave /kick 或 WS 资源清理)| +| 11 | S→C | `meeting.member.kicked` | 定向通知被踢者 | +| 12 | S→C | `meeting.host.changed` | 主持人变更 | +| 13 | S→C | `meeting.room.ended` | 会议被结束 | +| 14 | S→C | `meeting.member.state.changed` | 成员状态变化广播 | +| 15 | S→C | `meeting.member.producer.new` | 成员开启/关闭媒体流(`closed=true` 表示关闭)| +| 16 | S→C | `meeting.chat` | 会议内聊天(REST /chats 触发)| + +### 协议约定 + +- **C→S 白名单**:客户端仅可发起上表 C→S 列的 8 个事件,其余 `meeting.*` 事件若由客户端发送被静默丢弃。 +- **ACK 规则**:每个 C→S 事件服务端必回 `.ack`;成功 `code=0`,业务失败 `code=-1` + 中文 `message`(与 REST 领域错误口径一致)。 +- **错误码示例**:`会议不存在` / `你当前未在会议中` / `仅主持人可执行此操作` / `会议已结束`。 +- **资源追踪**:服务端对每用户在每会议的 transport/producer/consumer 用 Redis Set `echo:meeting:resources:{room_id}:{user_id}` 记录,WS 断开或 `room.leave` 时自动清理。 --- diff --git a/docs/plans/2026-04-21-phase2e-2-design.md b/docs/plans/2026-04-21-phase2e-2-design.md index a805312..bcb4cec 100644 --- a/docs/plans/2026-04-21-phase2e-2-design.md +++ b/docs/plans/2026-04-21-phase2e-2-design.md @@ -1088,6 +1088,8 @@ TabBar 「我的」红点逻辑不变(Phase 2e-1 已实现 `unreadTotal > 0` | 日期 | 作者 | 变更内容 | |---|---|---| | 2026-04-21 | Agent | 首版落盘。16 章节完整撰写,16 章节含 4 张 mermaid 图、3 张 DDL、1 份 REST API 清单、11 项关键决策记录 | +| 2026-04-21 | Agent | Task 5 落地偏离记录:`meeting_rooms.password` 字段改名为 `password_hash`(bcrypt 哈希);DAO `GetByID/GetByCode` 对 `ErrRecordNotFound` 统一返回 `(nil, nil)`;路径微调 `GET /rooms/mine` + `POST /invite-tokens/:token/redeem`;`kick` 请求体字段统一为 `user_id`(而非 `target_user_id`);新增 `MediaOrchestrator` 接口(Task 5 用 Noop 占位,Task 7 真实实现);WS 广播 Task 5 阶段暂用 `PublishToUser` 循环(Task 6 已替换为 `BroadcastToMeeting`) | +| 2026-04-21 | Agent | Task 6 落地偏离记录:§6.3 的 11 事件扩展为 **13 事件**(实际 16 含广播回包):新增 `meeting.chat`(REST 聊天广播)+ `meeting.member.producer.new`(produce.start / producer.close 的统一广播);`meeting.member.mute` + `meeting.member.video` 合并为 `meeting.member.state.changed`(加 `hand_raised` 举手字段 + `target_user_id` host 操作字段 + `actor_id`);`meeting.produce.stop` 重命名为 `meeting.producer.close`;`meeting.consume.resume` 暂时不落地(Consumer 创建时 `paused=true`,前端自己调 `/resume` 内部 REST);`meeting.room.info` 不落地(REST `/rooms/:code` 已覆盖);C→S 事件引入白名单常量 `MeetingWSClientEvents` 防伪造;新增 Redis 资源追踪 `echo:meeting:resources:{room_id}:{user_id}`(Set, TTL 1h)用于 WS 断开时自动清理 mediasoup 资源;新增 `MeetingBroadcaster` 统一广播层供 REST / WS 共用 | ---