docs: 完善项目文档体系
- 数据库 SQL 所有字段添加 COMMENT 注释,枚举字段详细标注各值含义 - 新增 docs/architecture/ 系统架构文档(分层架构、数据流、演进路径) - API 文档按模块拆分为 8 个独立文档(auth/contact/im/meeting/notify/admin/websocket) - 补充 README.md 项目说明(技术栈、架构、快速开始、功能规划、文档导航) Made-with: Cursor
This commit is contained in:
147
README.md
147
README.md
@@ -0,0 +1,147 @@
|
|||||||
|
# EchoChat - 音视频会议直播系统
|
||||||
|
|
||||||
|
EchoChat 是一套跨端可用、可扩展、可演进的实时音视频会议直播系统。支持即时聊天、多人音视频会议、互动直播等核心功能,采用控制面与媒体面彻底分离的架构设计。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
| 层级 | 技术 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 前台前端 | uniapp (Vue 3) + mediasoup-client | 多端适配(H5/App/小程序) |
|
||||||
|
| 后台管理端 | Vue 3 + Vite + Element Plus | PC Web 管理后台 |
|
||||||
|
| 后端服务 | Go (Gin + GORM + Wire + zap) | 业务逻辑、信令控制 |
|
||||||
|
| 媒体服务 | Node.js + mediasoup | SFU 媒体控制与转发 |
|
||||||
|
| 数据库 | PostgreSQL 16 | 持久化数据存储 |
|
||||||
|
| 缓存 | Redis 7 | 实时状态、会话缓存 |
|
||||||
|
| 部署 | Docker Compose / Nginx | 容器化部署,预留 K8s |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 系统架构
|
||||||
|
|
||||||
|
```
|
||||||
|
客户端 (uniapp / Vue3 管理端)
|
||||||
|
│
|
||||||
|
│ WebSocket + HTTP
|
||||||
|
│
|
||||||
|
Go 单体服务 (模块化)
|
||||||
|
│ ├── auth 用户认证鉴权
|
||||||
|
│ ├── im 即时通讯
|
||||||
|
│ ├── contact 联系人管理
|
||||||
|
│ ├── meeting 会议控制/信令
|
||||||
|
│ ├── notify 消息通知
|
||||||
|
│ └── admin 后台管理
|
||||||
|
│
|
||||||
|
├── PostgreSQL (持久化数据)
|
||||||
|
├── Redis (实时状态)
|
||||||
|
│
|
||||||
|
│ HTTP
|
||||||
|
│
|
||||||
|
mediasoup Node 服务
|
||||||
|
│ IPC
|
||||||
|
mediasoup Worker (C++ SFU)
|
||||||
|
```
|
||||||
|
|
||||||
|
核心设计思想:**控制面与媒体面分离**。Go 处理所有业务逻辑和信令控制,mediasoup 专注音视频媒体转发,音视频流直连 SFU Worker,不经过 Go 服务。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
EchoChat/
|
||||||
|
├── frontend/ # 前台用户端 (uniapp)
|
||||||
|
├── admin/ # 后台管理端 (Vue 3 + Element Plus)
|
||||||
|
├── backend/
|
||||||
|
│ └── go-service/ # Go 后端服务
|
||||||
|
├── media-server/ # mediasoup Node 媒体服务
|
||||||
|
├── deploy/ # 部署配置 (Docker / Nginx / K8s)
|
||||||
|
├── docs/ # 项目文档
|
||||||
|
│ ├── plans/ # 设计方案与实施计划
|
||||||
|
│ ├── api/ # API 接口文档
|
||||||
|
│ └── architecture/ # 架构设计文档
|
||||||
|
├── scripts/ # 脚本工具
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 环境要求
|
||||||
|
|
||||||
|
- Go 1.22+
|
||||||
|
- Node.js 18+
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- PostgreSQL 16 (通过 Docker)
|
||||||
|
- Redis 7 (通过 Docker)
|
||||||
|
|
||||||
|
### 1. 启动基础设施
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd deploy
|
||||||
|
docker compose -f docker-compose.dev.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 启动 Go 后端
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend/go-service
|
||||||
|
go mod tidy
|
||||||
|
go run cmd/server/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 启动前台前端
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run dev:h5
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 启动管理端
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd admin
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MVP 功能规划(第一期)
|
||||||
|
|
||||||
|
- [x] 设计方案与架构文档
|
||||||
|
- [ ] 用户注册/登录(邮箱+密码、用户名+密码)
|
||||||
|
- [ ] 即时聊天(单聊 + 群聊,文字/图片/文件)
|
||||||
|
- [ ] 联系人/好友管理
|
||||||
|
- [ ] 多人音视频会议(即时会议 + 预约会议)
|
||||||
|
- [ ] 消息通知系统
|
||||||
|
- [ ] 后台管理端(用户管理、会议监控、系统配置)
|
||||||
|
|
||||||
|
## 后续规划
|
||||||
|
|
||||||
|
- 屏幕共享
|
||||||
|
- 微信授权登录
|
||||||
|
- 互动直播(主播/观众/弹幕)
|
||||||
|
- 会议录制与回放
|
||||||
|
- 微服务拆分 + K8s 部署
|
||||||
|
- AI 辅助功能(语音转文字、会议纪要)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文档导航
|
||||||
|
|
||||||
|
| 文档 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 整体设计方案 | [docs/plans/2026-02-27-echochat-system-design.md](docs/plans/2026-02-27-echochat-system-design.md) | 系统完整设计方案 |
|
||||||
|
| 第一阶段实施计划 | [docs/plans/2026-02-27-phase1-foundation-and-auth.md](docs/plans/2026-02-27-phase1-foundation-and-auth.md) | 基础设施+用户体系实施步骤 |
|
||||||
|
| 系统架构文档 | [docs/architecture/system-architecture.md](docs/architecture/system-architecture.md) | 架构分层与技术选型 |
|
||||||
|
| API 接口文档 | [docs/api/](docs/api/) | 按模块拆分的 REST API + WebSocket 事件定义 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 开源协议
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|||||||
138
docs/api/README.md
Normal file
138
docs/api/README.md
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# EchoChat API 接口文档
|
||||||
|
|
||||||
|
> 本目录包含 EchoChat 系统所有接口定义,按功能模块拆分为独立文档,便于维护和查阅。
|
||||||
|
> 架构设计见 `docs/architecture/system-architecture.md`
|
||||||
|
> 完整设计方案见 `docs/plans/2026-02-27-echochat-system-design.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文档导航
|
||||||
|
|
||||||
|
| 文档 | 模块 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| [auth.md](auth.md) | 认证模块 | 用户注册、登录、Token 管理、个人信息 |
|
||||||
|
| [contact.md](contact.md) | 联系人模块 | 好友管理、好友分组 |
|
||||||
|
| [im.md](im.md) | 即时通讯模块 | 会话管理、消息历史、群聊管理 |
|
||||||
|
| [meeting.md](meeting.md) | 会议模块 | 即时会议、预约会议、加入/离开会议 |
|
||||||
|
| [notify.md](notify.md) | 通知模块 | 通知列表、已读管理 |
|
||||||
|
| [admin.md](admin.md) | 后台管理模块 | 用户管理、会议监控、系统配置、操作日志 |
|
||||||
|
| [websocket.md](websocket.md) | WebSocket 协议 | 实时消息、会议信令、在线状态事件 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 通用规范
|
||||||
|
|
||||||
|
### 基础 URL
|
||||||
|
|
||||||
|
| 环境 | 地址 |
|
||||||
|
|------|------|
|
||||||
|
| 开发环境 | `http://localhost:8080` |
|
||||||
|
| 生产环境 | `https://api.echochat.com`(待定) |
|
||||||
|
|
||||||
|
### 认证方式
|
||||||
|
|
||||||
|
除登录/注册等公开接口外,所有接口均需在请求头中携带 JWT Token:
|
||||||
|
|
||||||
|
```
|
||||||
|
Authorization: Bearer <access_token>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 统一响应格式
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": { ... },
|
||||||
|
"timestamp": 1740700000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**错误响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 1001,
|
||||||
|
"message": "参数错误:邮箱格式不正确",
|
||||||
|
"data": null,
|
||||||
|
"timestamp": 1740700000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 错误码定义
|
||||||
|
|
||||||
|
#### 通用错误码(1000-1099)
|
||||||
|
|
||||||
|
| 错误码 | 含义 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 0 | 成功 | 请求处理成功 |
|
||||||
|
| 1001 | 参数错误 | 请求参数缺失或格式不正确 |
|
||||||
|
| 1002 | 未认证 | Token 缺失、过期或无效 |
|
||||||
|
| 1003 | 权限不足 | 当前用户角色无权执行此操作 |
|
||||||
|
| 1004 | 资源不存在 | 请求的目标资源不存在 |
|
||||||
|
| 1005 | 操作重复 | 如重复注册、重复添加好友等 |
|
||||||
|
|
||||||
|
#### 认证模块错误码(2000-2099)
|
||||||
|
|
||||||
|
| 错误码 | 含义 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 2001 | 用户名已存在 | 注册时用户名重复 |
|
||||||
|
| 2002 | 邮箱已注册 | 注册时邮箱重复 |
|
||||||
|
| 2003 | 账号或密码错误 | 登录失败 |
|
||||||
|
| 2004 | 账号已被禁用 | 用户状态为禁用 |
|
||||||
|
|
||||||
|
#### IM 模块错误码(3000-3099)
|
||||||
|
|
||||||
|
| 错误码 | 含义 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 3001 | 会话不存在 | IM 会话 ID 无效 |
|
||||||
|
| 3002 | 非会话成员 | 用户不在该会话中 |
|
||||||
|
| 3003 | 已被禁言 | 用户在该群聊中被禁言 |
|
||||||
|
|
||||||
|
#### 会议模块错误码(4000-4099)
|
||||||
|
|
||||||
|
| 错误码 | 含义 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 4001 | 会议不存在 | 会议号无效 |
|
||||||
|
| 4002 | 会议密码错误 | 加入会议时密码不匹配 |
|
||||||
|
| 4003 | 会议已满 | 参会人数已达上限 |
|
||||||
|
| 4004 | 会议已结束 | 尝试加入已结束的会议 |
|
||||||
|
|
||||||
|
#### 系统错误码(5000-5099)
|
||||||
|
|
||||||
|
| 错误码 | 含义 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 5001 | 系统内部错误 | 服务端未知错误 |
|
||||||
|
| 5002 | 服务暂不可用 | 依赖服务不可用(数据库、Redis 等) |
|
||||||
|
|
||||||
|
### 分页规范
|
||||||
|
|
||||||
|
支持分页的接口统一使用以下查询参数:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| page | int | 1 | 页码,从 1 开始 |
|
||||||
|
| page_size | int | 20 | 每页数量,最大 100 |
|
||||||
|
|
||||||
|
分页响应格式:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"list": [ ... ],
|
||||||
|
"total": 150,
|
||||||
|
"page": 1,
|
||||||
|
"page_size": 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文档维护规则
|
||||||
|
|
||||||
|
1. **新增接口时**:在对应模块文档中追加,保持格式一致
|
||||||
|
2. **接口变更时**:同步更新文档,必要时在接口描述中标注版本信息
|
||||||
|
3. **新增模块时**:创建新的模块文档,在本 README 导航表中添加链接
|
||||||
|
4. **错误码新增时**:在本文档的错误码定义中追加,保持各模块错误码区间不重叠
|
||||||
280
docs/api/admin.md
Normal file
280
docs/api/admin.md
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
# 后台管理模块 API (Admin)
|
||||||
|
|
||||||
|
> 通用规范(认证方式、响应格式、错误码)见 [README.md](README.md)
|
||||||
|
> 以下所有接口(除管理员登录外)均需要 **JWT 认证 + admin/super_admin 角色**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 接口列表
|
||||||
|
|
||||||
|
### 认证
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| POST | /api/v1/admin/auth/login | 公开 | 管理员登录 |
|
||||||
|
|
||||||
|
### 用户管理
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| GET | /api/v1/admin/users | admin | 获取用户列表 |
|
||||||
|
| GET | /api/v1/admin/users/:id | admin | 获取用户详情 |
|
||||||
|
| PUT | /api/v1/admin/users/:id/status | admin | 更新用户状态 |
|
||||||
|
| PUT | /api/v1/admin/users/:id/role | super_admin | 分配用户角色 |
|
||||||
|
| POST | /api/v1/admin/users | admin | 管理员创建用户 |
|
||||||
|
| GET | /api/v1/admin/users/:id/meetings | admin | 获取用户会议记录 |
|
||||||
|
|
||||||
|
### 会议管理
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| GET | /api/v1/admin/meetings | admin | 获取会议列表 |
|
||||||
|
| GET | /api/v1/admin/meetings/:id | admin | 获取会议详情 |
|
||||||
|
| PUT | /api/v1/admin/meetings/:id/close | admin | 强制结束会议 |
|
||||||
|
| GET | /api/v1/admin/meetings/stats | admin | 获取会议统计 |
|
||||||
|
|
||||||
|
### 系统管理
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| GET | /api/v1/admin/dashboard | admin | 获取仪表盘数据 |
|
||||||
|
| GET | /api/v1/admin/logs | admin | 获取操作日志 |
|
||||||
|
| GET | /api/v1/admin/system/config | super_admin | 获取系统配置 |
|
||||||
|
| PUT | /api/v1/admin/system/config | super_admin | 更新系统配置 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 认证
|
||||||
|
|
||||||
|
### 1. 管理员登录
|
||||||
|
|
||||||
|
`POST /api/v1/admin/auth/login`
|
||||||
|
|
||||||
|
**权限:** 公开
|
||||||
|
|
||||||
|
**请求参数:** 与用户登录相同
|
||||||
|
|
||||||
|
**说明:** 登录后会额外验证用户是否拥有 admin 或 super_admin 角色,如果没有对应角色则返回 1003(权限不足)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 用户管理
|
||||||
|
|
||||||
|
### 2. 获取用户列表
|
||||||
|
|
||||||
|
`GET /api/v1/admin/users`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**查询参数:**
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| keyword | string | 无 | 搜索关键词(匹配用户名/邮箱/昵称) |
|
||||||
|
| status | int | 无 | 按状态筛选:1=正常,2=禁用,3=注销 |
|
||||||
|
| role | string | 无 | 按角色筛选:user / admin / super_admin |
|
||||||
|
| page | int | 1 | 页码 |
|
||||||
|
| page_size | int | 20 | 每页数量 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 获取用户详情
|
||||||
|
|
||||||
|
`GET /api/v1/admin/users/:id`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "zhangsan",
|
||||||
|
"email": "zhangsan@example.com",
|
||||||
|
"nickname": "张三",
|
||||||
|
"avatar": "https://...",
|
||||||
|
"gender": 1,
|
||||||
|
"phone": "13800138000",
|
||||||
|
"status": 1,
|
||||||
|
"roles": ["user"],
|
||||||
|
"last_login_at": "2026-02-27T10:00:00Z",
|
||||||
|
"last_login_ip": "192.168.1.100",
|
||||||
|
"created_at": "2026-02-20T08:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. 更新用户状态
|
||||||
|
|
||||||
|
`PUT /api/v1/admin/users/:id/status`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| status | int | 是 | 目标状态:1=正常(启用),2=禁用 |
|
||||||
|
|
||||||
|
**说明:** 禁用用户后,该用户的所有活跃 Token 将被清除,正在进行的 WebSocket 连接将被断开。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. 分配用户角色
|
||||||
|
|
||||||
|
`PUT /api/v1/admin/users/:id/role`
|
||||||
|
|
||||||
|
**权限:** super_admin
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| role_code | string | 是 | 角色代码:user / admin / super_admin |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. 管理员创建用户
|
||||||
|
|
||||||
|
`POST /api/v1/admin/users`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**请求参数:** 同用户注册接口,额外支持:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| role_code | string | 否 | 指定角色,默认为 user |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. 获取用户会议记录
|
||||||
|
|
||||||
|
`GET /api/v1/admin/users/:id/meetings`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**查询参数:**
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| status | string | 无 | ongoing=进行中,upcoming=即将开始,ended=已结束 |
|
||||||
|
| page | int | 1 | 页码 |
|
||||||
|
| page_size | int | 20 | 每页数量 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 会议管理
|
||||||
|
|
||||||
|
### 8. 获取会议列表
|
||||||
|
|
||||||
|
`GET /api/v1/admin/meetings`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**查询参数:** 支持按 status、type、keyword(会议标题)筛选,支持分页
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. 获取会议详情
|
||||||
|
|
||||||
|
`GET /api/v1/admin/meetings/:id`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10. 强制结束会议
|
||||||
|
|
||||||
|
`PUT /api/v1/admin/meetings/:id/close`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**说明:** 强制结束后,所有参会者将收到会议结束通知,所有媒体资源将被回收。操作将记录到管理日志。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 11. 获取会议统计
|
||||||
|
|
||||||
|
`GET /api/v1/admin/meetings/stats`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"total_meetings": 1500,
|
||||||
|
"ongoing_meetings": 5,
|
||||||
|
"today_meetings": 23,
|
||||||
|
"total_participants": 8500,
|
||||||
|
"avg_duration": 1800
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 系统管理
|
||||||
|
|
||||||
|
### 12. 获取仪表盘数据
|
||||||
|
|
||||||
|
`GET /api/v1/admin/dashboard`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"total_users": 1200,
|
||||||
|
"online_users": 85,
|
||||||
|
"today_new_users": 12,
|
||||||
|
"ongoing_meetings": 5,
|
||||||
|
"today_meetings": 23,
|
||||||
|
"today_messages": 5600
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 13. 获取操作日志
|
||||||
|
|
||||||
|
`GET /api/v1/admin/logs`
|
||||||
|
|
||||||
|
**权限:** admin
|
||||||
|
|
||||||
|
**查询参数:**
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| module | string | 无 | 按模块筛选 |
|
||||||
|
| action | string | 无 | 按操作类型筛选 |
|
||||||
|
| admin_id | int | 无 | 按操作管理员筛选 |
|
||||||
|
| page | int | 1 | 页码 |
|
||||||
|
| page_size | int | 20 | 每页数量 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 14. 获取系统配置
|
||||||
|
|
||||||
|
`GET /api/v1/admin/system/config`
|
||||||
|
|
||||||
|
**权限:** super_admin
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 15. 更新系统配置
|
||||||
|
|
||||||
|
`PUT /api/v1/admin/system/config`
|
||||||
|
|
||||||
|
**权限:** super_admin
|
||||||
203
docs/api/auth.md
Normal file
203
docs/api/auth.md
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# 认证模块 API (Auth)
|
||||||
|
|
||||||
|
> 通用规范(认证方式、响应格式、错误码)见 [README.md](README.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 接口列表
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| POST | /api/v1/auth/register | 公开 | 用户注册 |
|
||||||
|
| POST | /api/v1/auth/login | 公开 | 用户登录 |
|
||||||
|
| POST | /api/v1/auth/logout | 需认证 | 退出登录 |
|
||||||
|
| POST | /api/v1/auth/refresh-token | 公开 | 刷新 Token |
|
||||||
|
| GET | /api/v1/auth/profile | 需认证 | 获取个人信息 |
|
||||||
|
| PUT | /api/v1/auth/profile | 需认证 | 更新个人信息 |
|
||||||
|
| PUT | /api/v1/auth/password | 需认证 | 修改密码 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 用户注册
|
||||||
|
|
||||||
|
`POST /api/v1/auth/register`
|
||||||
|
|
||||||
|
**权限:** 公开
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 规则 | 说明 |
|
||||||
|
|------|------|------|------|------|
|
||||||
|
| username | string | 是 | 3-50 字符,字母数字下划线 | 用户名 |
|
||||||
|
| email | string | 是 | 合法邮箱格式 | 邮箱地址 |
|
||||||
|
| password | string | 是 | 6-50 字符 | 登录密码 |
|
||||||
|
| nickname | string | 否 | 最多 50 字符 | 昵称,默认与用户名相同 |
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "zhangsan",
|
||||||
|
"email": "zhangsan@example.com",
|
||||||
|
"password": "123456",
|
||||||
|
"nickname": "张三"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"token": "eyJhbGciOiJIUzI1NiIs...",
|
||||||
|
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||||
|
"expires_in": 604800,
|
||||||
|
"user": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "zhangsan",
|
||||||
|
"email": "zhangsan@example.com",
|
||||||
|
"nickname": "张三",
|
||||||
|
"avatar": "",
|
||||||
|
"roles": ["user"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**可能的错误码:** 1001, 2001, 2002
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 用户登录
|
||||||
|
|
||||||
|
`POST /api/v1/auth/login`
|
||||||
|
|
||||||
|
**权限:** 公开
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| account | string | 是 | 用户名或邮箱(自动识别格式) |
|
||||||
|
| password | string | 是 | 登录密码 |
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"account": "zhangsan",
|
||||||
|
"password": "123456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**成功响应:** 与注册接口返回格式一致
|
||||||
|
|
||||||
|
**可能的错误码:** 1001, 2003, 2004
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 退出登录
|
||||||
|
|
||||||
|
`POST /api/v1/auth/logout`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**说明:** 服务端清除 Redis 中的 Token 记录,客户端需同步清除本地存储的 Token。
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 刷新 Token
|
||||||
|
|
||||||
|
`POST /api/v1/auth/refresh-token`
|
||||||
|
|
||||||
|
**权限:** 公开(携带 refresh_token)
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| refresh_token | string | 是 | 刷新令牌 |
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"token": "eyJhbG...(新 Access Token)",
|
||||||
|
"refresh_token": "eyJhbG...(新 Refresh Token)",
|
||||||
|
"expires_in": 604800
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**可能的错误码:** 1002
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 获取个人信息
|
||||||
|
|
||||||
|
`GET /api/v1/auth/profile`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "zhangsan",
|
||||||
|
"email": "zhangsan@example.com",
|
||||||
|
"nickname": "张三",
|
||||||
|
"avatar": "https://cdn.echochat.com/avatar/1.jpg",
|
||||||
|
"gender": 1,
|
||||||
|
"phone": "13800138000",
|
||||||
|
"roles": ["user"],
|
||||||
|
"created_at": "2026-02-27T10:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 更新个人信息
|
||||||
|
|
||||||
|
`PUT /api/v1/auth/profile`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数(均为可选,只传需要修改的字段):**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| nickname | string | 否 | 新昵称 |
|
||||||
|
| avatar | string | 否 | 新头像 URL |
|
||||||
|
| gender | int | 否 | 性别:0=未知,1=男,2=女 |
|
||||||
|
| phone | string | 否 | 手机号 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 修改密码
|
||||||
|
|
||||||
|
`PUT /api/v1/auth/password`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| old_password | string | 是 | 原密码 |
|
||||||
|
| new_password | string | 是 | 新密码(6-50 字符) |
|
||||||
|
|
||||||
|
**可能的错误码:** 1001, 2003(原密码错误)
|
||||||
164
docs/api/contact.md
Normal file
164
docs/api/contact.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
# 联系人模块 API (Contact)
|
||||||
|
|
||||||
|
> 通用规范(认证方式、响应格式、错误码)见 [README.md](README.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 接口列表
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| GET | /api/v1/contacts | 需认证 | 获取好友列表 |
|
||||||
|
| POST | /api/v1/contacts/request | 需认证 | 发送好友申请 |
|
||||||
|
| POST | /api/v1/contacts/accept | 需认证 | 接受好友申请 |
|
||||||
|
| POST | /api/v1/contacts/reject | 需认证 | 拒绝好友申请 |
|
||||||
|
| DELETE | /api/v1/contacts/:id | 需认证 | 删除好友 |
|
||||||
|
| PUT | /api/v1/contacts/:id/remark | 需认证 | 修改好友备注 |
|
||||||
|
| GET | /api/v1/contacts/groups | 需认证 | 获取好友分组列表 |
|
||||||
|
| POST | /api/v1/contacts/groups | 需认证 | 创建好友分组 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 获取好友列表
|
||||||
|
|
||||||
|
`GET /api/v1/contacts`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**查询参数:**
|
||||||
|
|
||||||
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| group_id | int | 否 | 按分组筛选 |
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"friend_id": 2,
|
||||||
|
"username": "lisi",
|
||||||
|
"nickname": "李四",
|
||||||
|
"remark": "我的同事",
|
||||||
|
"avatar": "https://cdn.echochat.com/avatar/2.jpg",
|
||||||
|
"online": true,
|
||||||
|
"group_id": 1,
|
||||||
|
"group_name": "同事"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 发送好友申请
|
||||||
|
|
||||||
|
`POST /api/v1/contacts/request`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| target_id | int | 是 | 目标用户 ID |
|
||||||
|
| message | string | 否 | 申请附言,如"我是张三的同事" |
|
||||||
|
|
||||||
|
**可能的错误码:** 1004(用户不存在),1005(已是好友或已发送过申请)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 接受好友申请
|
||||||
|
|
||||||
|
`POST /api/v1/contacts/accept`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| friendship_id | int | 是 | 好友关系记录 ID |
|
||||||
|
|
||||||
|
**说明:** 接受后系统自动创建双向好友关系,并发送通知给对方。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 拒绝好友申请
|
||||||
|
|
||||||
|
`POST /api/v1/contacts/reject`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| friendship_id | int | 是 | 好友关系记录 ID |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 删除好友
|
||||||
|
|
||||||
|
`DELETE /api/v1/contacts/:id`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**路径参数:** `id` — 好友关系记录 ID
|
||||||
|
|
||||||
|
**说明:** 删除后双向关系均解除,关联的单聊会话不会删除(消息记录保留)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 修改好友备注
|
||||||
|
|
||||||
|
`PUT /api/v1/contacts/:id/remark`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**路径参数:** `id` — 好友关系记录 ID
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| remark | string | 是 | 新备注名,最多 50 字符 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 获取好友分组列表
|
||||||
|
|
||||||
|
`GET /api/v1/contacts/groups`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": [
|
||||||
|
{ "id": 1, "name": "同事", "sort_order": 0, "count": 15 },
|
||||||
|
{ "id": 2, "name": "朋友", "sort_order": 1, "count": 8 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 创建好友分组
|
||||||
|
|
||||||
|
`POST /api/v1/contacts/groups`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| name | string | 是 | 分组名称,最多 50 字符 |
|
||||||
|
|
||||||
|
**可能的错误码:** 1005(同名分组已存在)
|
||||||
208
docs/api/im.md
Normal file
208
docs/api/im.md
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
# 即时通讯模块 API (IM)
|
||||||
|
|
||||||
|
> 通用规范(认证方式、响应格式、错误码)见 [README.md](README.md)
|
||||||
|
> 消息的实时收发通过 WebSocket 完成,见 [websocket.md](websocket.md)
|
||||||
|
> 本文档中的接口用于会话管理和消息历史查询等非实时操作。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 接口列表
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| GET | /api/v1/conversations | 需认证 | 获取会话列表 |
|
||||||
|
| POST | /api/v1/conversations | 需认证 | 创建群聊 |
|
||||||
|
| GET | /api/v1/conversations/:id | 需认证 | 获取会话详情 |
|
||||||
|
| GET | /api/v1/conversations/:id/messages | 需认证 | 获取消息历史 |
|
||||||
|
| POST | /api/v1/conversations/:id/members | 需认证 | 邀请成员加入群聊 |
|
||||||
|
| DELETE | /api/v1/conversations/:id/members/:uid | 需认证 | 移除群聊成员 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 获取会话列表
|
||||||
|
|
||||||
|
`GET /api/v1/conversations`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**说明:** 返回当前用户的所有会话,按最后消息时间倒序排列。单聊会话的 `name`/`avatar` 为空,前端应使用 `target_user` 的信息展示。
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": 1,
|
||||||
|
"name": "",
|
||||||
|
"avatar": "",
|
||||||
|
"target_user": {
|
||||||
|
"id": 2,
|
||||||
|
"nickname": "李四",
|
||||||
|
"avatar": "https://cdn.echochat.com/avatar/2.jpg",
|
||||||
|
"online": true
|
||||||
|
},
|
||||||
|
"last_message": {
|
||||||
|
"id": 100,
|
||||||
|
"type": 1,
|
||||||
|
"content": "你好",
|
||||||
|
"sender_id": 2,
|
||||||
|
"created_at": "2026-02-27T10:30:00Z"
|
||||||
|
},
|
||||||
|
"unread_count": 3,
|
||||||
|
"is_pinned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": 2,
|
||||||
|
"name": "产品讨论组",
|
||||||
|
"avatar": "https://cdn.echochat.com/group/5.jpg",
|
||||||
|
"target_user": null,
|
||||||
|
"last_message": {
|
||||||
|
"id": 205,
|
||||||
|
"type": 1,
|
||||||
|
"content": "明天开会",
|
||||||
|
"sender_id": 3,
|
||||||
|
"created_at": "2026-02-27T11:00:00Z"
|
||||||
|
},
|
||||||
|
"unread_count": 0,
|
||||||
|
"is_pinned": true,
|
||||||
|
"member_count": 8
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 创建群聊
|
||||||
|
|
||||||
|
`POST /api/v1/conversations`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| name | string | 是 | 群聊名称 |
|
||||||
|
| member_ids | int[] | 是 | 初始成员用户 ID 列表(不含自己,至少 2 人) |
|
||||||
|
|
||||||
|
**说明:** 创建者自动成为群主(role=2),被邀请的成员为普通成员(role=0)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 获取会话详情
|
||||||
|
|
||||||
|
`GET /api/v1/conversations/:id`
|
||||||
|
|
||||||
|
**权限:** 需认证,且为该会话成员
|
||||||
|
|
||||||
|
**成功响应(群聊示例):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"id": 5,
|
||||||
|
"type": 2,
|
||||||
|
"name": "产品讨论组",
|
||||||
|
"avatar": "https://cdn.echochat.com/group/5.jpg",
|
||||||
|
"owner_id": 1,
|
||||||
|
"max_members": 200,
|
||||||
|
"member_count": 8,
|
||||||
|
"members": [
|
||||||
|
{ "user_id": 1, "nickname": "张三", "role": 2, "online": true },
|
||||||
|
{ "user_id": 2, "nickname": "李四", "role": 0, "online": false }
|
||||||
|
],
|
||||||
|
"created_at": "2026-02-20T09:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 获取消息历史
|
||||||
|
|
||||||
|
`GET /api/v1/conversations/:id/messages`
|
||||||
|
|
||||||
|
**权限:** 需认证,且为该会话成员
|
||||||
|
|
||||||
|
**查询参数:**
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| before_id | int | 无 | 获取此消息 ID 之前的消息(用于向上翻页加载历史) |
|
||||||
|
| limit | int | 30 | 每次获取数量,最大 50 |
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"id": 98,
|
||||||
|
"sender_id": 1,
|
||||||
|
"sender_name": "张三",
|
||||||
|
"sender_avatar": "https://...",
|
||||||
|
"type": 1,
|
||||||
|
"content": "明天几点开会?",
|
||||||
|
"extra": {},
|
||||||
|
"status": 1,
|
||||||
|
"created_at": "2026-02-27T10:28:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 99,
|
||||||
|
"sender_id": 2,
|
||||||
|
"sender_name": "李四",
|
||||||
|
"sender_avatar": "https://...",
|
||||||
|
"type": 2,
|
||||||
|
"content": "",
|
||||||
|
"extra": {
|
||||||
|
"url": "https://cdn.echochat.com/img/xxx.jpg",
|
||||||
|
"width": 800,
|
||||||
|
"height": 600,
|
||||||
|
"thumbnail": "https://cdn.echochat.com/img/xxx_thumb.jpg"
|
||||||
|
},
|
||||||
|
"status": 1,
|
||||||
|
"created_at": "2026-02-27T10:29:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"has_more": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 邀请成员加入群聊
|
||||||
|
|
||||||
|
`POST /api/v1/conversations/:id/members`
|
||||||
|
|
||||||
|
**权限:** 需认证,且为该群聊成员
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| user_ids | int[] | 是 | 要邀请的用户 ID 列表 |
|
||||||
|
|
||||||
|
**可能的错误码:** 3001(会话不存在),3002(非会话成员),4003(超出人数上限)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 移除群聊成员
|
||||||
|
|
||||||
|
`DELETE /api/v1/conversations/:id/members/:uid`
|
||||||
|
|
||||||
|
**权限:** 需认证,且为群主或管理员
|
||||||
|
|
||||||
|
**路径参数:**
|
||||||
|
- `id` — 会话 ID
|
||||||
|
- `uid` — 被移除的用户 ID
|
||||||
|
|
||||||
|
**可能的错误码:** 3001, 3002, 1003(非群主/管理员无权操作)
|
||||||
180
docs/api/meeting.md
Normal file
180
docs/api/meeting.md
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
# 会议模块 API (Meeting)
|
||||||
|
|
||||||
|
> 通用规范(认证方式、响应格式、错误码)见 [README.md](README.md)
|
||||||
|
> 会议中的实时信令(Transport/Producer/Consumer)通过 WebSocket 完成,见 [websocket.md](websocket.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 接口列表
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| POST | /api/v1/meetings | 需认证 | 创建即时会议 |
|
||||||
|
| POST | /api/v1/meetings/schedule | 需认证 | 预约会议 |
|
||||||
|
| GET | /api/v1/meetings/:code | 需认证 | 获取会议信息 |
|
||||||
|
| POST | /api/v1/meetings/:code/join | 需认证 | 加入会议 |
|
||||||
|
| POST | /api/v1/meetings/:code/leave | 需认证 | 离开会议 |
|
||||||
|
| GET | /api/v1/meetings/upcoming | 需认证 | 获取即将开始的会议 |
|
||||||
|
| GET | /api/v1/meetings/ongoing | 需认证 | 获取进行中的会议 |
|
||||||
|
| GET | /api/v1/meetings/history | 需认证 | 获取历史会议 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 创建即时会议
|
||||||
|
|
||||||
|
`POST /api/v1/meetings`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| title | string | 是 | 会议标题 |
|
||||||
|
| password | string | 否 | 会议密码,不设则任何人可加入 |
|
||||||
|
| max_members | int | 否 | 最大人数,默认 50 |
|
||||||
|
| settings | object | 否 | 会议设置 |
|
||||||
|
|
||||||
|
**settings 可选字段:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| mute_on_join | bool | false | 入会时自动静音 |
|
||||||
|
| allow_recording | bool | false | 是否允许录制(预留) |
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"room_code": "123-456-789",
|
||||||
|
"title": "产品需求讨论",
|
||||||
|
"type": 1,
|
||||||
|
"status": 1,
|
||||||
|
"host_id": 1,
|
||||||
|
"max_members": 50,
|
||||||
|
"created_at": "2026-02-27T10:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 预约会议
|
||||||
|
|
||||||
|
`POST /api/v1/meetings/schedule`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| title | string | 是 | 会议标题 |
|
||||||
|
| scheduled_at | string | 是 | 预约时间(ISO 8601,如 "2026-03-01T14:00:00Z") |
|
||||||
|
| password | string | 否 | 会议密码 |
|
||||||
|
| max_members | int | 否 | 最大人数 |
|
||||||
|
| invite_user_ids | int[] | 否 | 预先邀请的用户 ID 列表 |
|
||||||
|
| settings | object | 否 | 会议设置 |
|
||||||
|
|
||||||
|
**说明:** 预约会议创建后 status=0(未开始),被邀请的用户会收到通知。系统在预约时间前 15 分钟和 5 分钟各推送一次提醒。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 获取会议信息
|
||||||
|
|
||||||
|
`GET /api/v1/meetings/:code`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**路径参数:** `code` — 会议号
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"room_code": "123-456-789",
|
||||||
|
"title": "产品需求讨论",
|
||||||
|
"type": 1,
|
||||||
|
"status": 1,
|
||||||
|
"host": {
|
||||||
|
"id": 1,
|
||||||
|
"nickname": "张三",
|
||||||
|
"avatar": "https://..."
|
||||||
|
},
|
||||||
|
"has_password": true,
|
||||||
|
"max_members": 50,
|
||||||
|
"current_members": 5,
|
||||||
|
"started_at": "2026-02-27T10:00:00Z",
|
||||||
|
"participants": [
|
||||||
|
{ "user_id": 1, "nickname": "张三", "role": 1, "joined_at": "2026-02-27T10:00:00Z" },
|
||||||
|
{ "user_id": 2, "nickname": "李四", "role": 0, "joined_at": "2026-02-27T10:01:00Z" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 加入会议
|
||||||
|
|
||||||
|
`POST /api/v1/meetings/:code/join`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| password | string | 否 | 会议密码(如果会议设有密码) |
|
||||||
|
|
||||||
|
**成功响应包含加入会议所需的信令参数。**
|
||||||
|
|
||||||
|
**可能的错误码:** 4001, 4002, 4003, 4004
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 离开会议
|
||||||
|
|
||||||
|
`POST /api/v1/meetings/:code/leave`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**说明:** 离开后系统自动计算参会时长。如果主持人离开且没有联合主持人,会议将自动结束。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 获取即将开始的会议
|
||||||
|
|
||||||
|
`GET /api/v1/meetings/upcoming`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**说明:** 返回当前用户被邀请的、尚未开始的预约会议列表,按预约时间升序排列。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 获取进行中的会议
|
||||||
|
|
||||||
|
`GET /api/v1/meetings/ongoing`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**说明:** 返回当前用户正在参与的或被邀请的进行中会议。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 获取历史会议
|
||||||
|
|
||||||
|
`GET /api/v1/meetings/history`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**查询参数:** 支持分页(page, page_size)
|
||||||
|
|
||||||
|
**说明:** 返回当前用户参与过的已结束会议,按结束时间倒序排列。
|
||||||
93
docs/api/notify.md
Normal file
93
docs/api/notify.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# 通知模块 API (Notify)
|
||||||
|
|
||||||
|
> 通用规范(认证方式、响应格式、错误码)见 [README.md](README.md)
|
||||||
|
> 新通知的实时推送通过 WebSocket 完成,见 [websocket.md](websocket.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 接口列表
|
||||||
|
|
||||||
|
| 方法 | 路径 | 权限 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| GET | /api/v1/notifications | 需认证 | 获取通知列表 |
|
||||||
|
| PUT | /api/v1/notifications/:id/read | 需认证 | 标记通知已读 |
|
||||||
|
| PUT | /api/v1/notifications/read-all | 需认证 | 全部标记已读 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 获取通知列表
|
||||||
|
|
||||||
|
`GET /api/v1/notifications`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**查询参数:**
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| is_read | bool | 无 | 筛选已读/未读,不传则返回全部 |
|
||||||
|
| type | string | 无 | 筛选通知类型(meeting_invite / friend_request / friend_accepted / meeting_reminder / system) |
|
||||||
|
| page | int | 1 | 页码 |
|
||||||
|
| page_size | int | 20 | 每页数量 |
|
||||||
|
|
||||||
|
**成功响应:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "meeting_invite",
|
||||||
|
"title": "会议邀请",
|
||||||
|
"content": "张三邀请你参加会议「产品需求讨论」",
|
||||||
|
"extra": {
|
||||||
|
"room_code": "123-456-789",
|
||||||
|
"room_title": "产品需求讨论",
|
||||||
|
"from_user_id": 1,
|
||||||
|
"from_username": "zhangsan"
|
||||||
|
},
|
||||||
|
"is_read": false,
|
||||||
|
"created_at": "2026-02-27T10:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"type": "friend_request",
|
||||||
|
"title": "好友申请",
|
||||||
|
"content": "李四请求添加你为好友",
|
||||||
|
"extra": {
|
||||||
|
"from_user_id": 2,
|
||||||
|
"from_username": "lisi",
|
||||||
|
"message": "我是你的同事"
|
||||||
|
},
|
||||||
|
"is_read": false,
|
||||||
|
"created_at": "2026-02-27T09:30:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 15,
|
||||||
|
"page": 1,
|
||||||
|
"page_size": 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 标记通知已读
|
||||||
|
|
||||||
|
`PUT /api/v1/notifications/:id/read`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**路径参数:** `id` — 通知 ID
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 全部标记已读
|
||||||
|
|
||||||
|
`PUT /api/v1/notifications/read-all`
|
||||||
|
|
||||||
|
**权限:** 需认证
|
||||||
|
|
||||||
|
**说明:** 将当前用户的所有未读通知标记为已读。
|
||||||
397
docs/api/websocket.md
Normal file
397
docs/api/websocket.md
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
# WebSocket 事件协议
|
||||||
|
|
||||||
|
> 通用规范(认证方式、响应格式、错误码)见 [README.md](README.md)
|
||||||
|
> 本文档定义 EchoChat 系统中所有 WebSocket 实时通信事件。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 连接说明
|
||||||
|
|
||||||
|
### 连接地址
|
||||||
|
|
||||||
|
| 环境 | 地址 |
|
||||||
|
|------|------|
|
||||||
|
| 开发环境 | `ws://localhost:8080/ws?token=<access_token>` |
|
||||||
|
| 生产环境 | `wss://api.echochat.com/ws?token=<access_token>` |
|
||||||
|
|
||||||
|
### 连接认证
|
||||||
|
|
||||||
|
通过 URL 查询参数 `token` 携带 JWT Access Token,服务端验证通过后建立连接。
|
||||||
|
|
||||||
|
### 心跳机制
|
||||||
|
|
||||||
|
- 客户端每 **30 秒** 发送一次 ping 帧
|
||||||
|
- 服务端响应 pong 帧
|
||||||
|
- 如果 **90 秒** 内未收到客户端心跳,服务端主动断开连接
|
||||||
|
|
||||||
|
### 断线重连
|
||||||
|
|
||||||
|
- 客户端检测到连接断开后自动重连
|
||||||
|
- 重连间隔采用指数退避:1s → 2s → 4s → 8s → 16s → 最大 30s
|
||||||
|
- 重连成功后拉取离线消息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 消息格式
|
||||||
|
|
||||||
|
### 客户端发送格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event": "im.message.send",
|
||||||
|
"seq": 1001,
|
||||||
|
"data": { ... },
|
||||||
|
"timestamp": 1740700000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| event | string | 事件名称,格式:`{模块}.{对象}.{动作}` |
|
||||||
|
| seq | int | 消息序列号,客户端自增,用于匹配请求和响应 |
|
||||||
|
| data | object | 事件数据 |
|
||||||
|
| timestamp | int | 发送时间戳(秒) |
|
||||||
|
|
||||||
|
### 服务端响应格式(ACK)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event": "im.message.send.ack",
|
||||||
|
"seq": 1001,
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": { "msg_id": 10086 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 服务端推送格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event": "im.message.new",
|
||||||
|
"data": { ... },
|
||||||
|
"timestamp": 1740700000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
推送类消息没有 seq 字段(不需要客户端确认)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 即时通讯事件
|
||||||
|
|
||||||
|
### im.message.send
|
||||||
|
|
||||||
|
**方向:** 客户端 → 服务端
|
||||||
|
|
||||||
|
**说明:** 发送消息到会话
|
||||||
|
|
||||||
|
**data 参数:**
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| conversation_id | int | 是 | 目标会话 ID |
|
||||||
|
| type | int | 是 | 消息类型:1=文本,2=图片,3=文件,4=语音 |
|
||||||
|
| content | string | 否 | 文本内容 |
|
||||||
|
| extra | object | 否 | 附加数据(图片/文件信息) |
|
||||||
|
|
||||||
|
**ACK 响应 data:** `{ "msg_id": 10086 }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### im.message.new
|
||||||
|
|
||||||
|
**方向:** 服务端 → 客户端
|
||||||
|
|
||||||
|
**说明:** 收到新消息推送
|
||||||
|
|
||||||
|
**data 内容:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 10086,
|
||||||
|
"conversation_id": 1,
|
||||||
|
"sender_id": 2,
|
||||||
|
"sender_name": "李四",
|
||||||
|
"sender_avatar": "https://...",
|
||||||
|
"type": 1,
|
||||||
|
"content": "你好",
|
||||||
|
"extra": {},
|
||||||
|
"created_at": "2026-02-27T10:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### im.message.revoke
|
||||||
|
|
||||||
|
**方向:** 客户端 → 服务端
|
||||||
|
|
||||||
|
**说明:** 撤回消息(发送后 2 分钟内)
|
||||||
|
|
||||||
|
**data 参数:** `{ "message_id": 10086 }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### im.message.read
|
||||||
|
|
||||||
|
**方向:** 客户端 → 服务端
|
||||||
|
|
||||||
|
**说明:** 消息已读回执
|
||||||
|
|
||||||
|
**data 参数:** `{ "conversation_id": 1, "message_id": 10086 }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### im.typing.start
|
||||||
|
|
||||||
|
**方向:** 客户端 → 服务端
|
||||||
|
|
||||||
|
**说明:** 通知对方"正在输入"
|
||||||
|
|
||||||
|
**data 参数:** `{ "conversation_id": 1 }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### im.typing.stop
|
||||||
|
|
||||||
|
**方向:** 客户端 → 服务端
|
||||||
|
|
||||||
|
**说明:** 停止输入
|
||||||
|
|
||||||
|
**data 参数:** `{ "conversation_id": 1 }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 会议信令事件
|
||||||
|
|
||||||
|
### 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": "..." }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 用户状态事件
|
||||||
|
|
||||||
|
### user.status.online
|
||||||
|
|
||||||
|
**方向:** 服务端 → 客户端
|
||||||
|
|
||||||
|
**说明:** 好友上线通知
|
||||||
|
|
||||||
|
**data 内容:** `{ "user_id": 2, "nickname": "李四" }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### user.status.offline
|
||||||
|
|
||||||
|
**方向:** 服务端 → 客户端
|
||||||
|
|
||||||
|
**说明:** 好友离线通知
|
||||||
|
|
||||||
|
**data 内容:** `{ "user_id": 2 }`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 通知事件
|
||||||
|
|
||||||
|
### notify.new
|
||||||
|
|
||||||
|
**方向:** 服务端 → 客户端
|
||||||
|
|
||||||
|
**说明:** 新通知推送(通用)
|
||||||
|
|
||||||
|
**data 内容:** 与 Notify API 获取通知列表中的单条通知格式一致
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### notify.meeting.invite
|
||||||
|
|
||||||
|
**方向:** 服务端 → 客户端
|
||||||
|
|
||||||
|
**说明:** 会议邀请推送
|
||||||
|
|
||||||
|
**data 内容:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"room_code": "123-456-789",
|
||||||
|
"title": "产品需求讨论",
|
||||||
|
"from_user_id": 1,
|
||||||
|
"from_nickname": "张三"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### notify.friend.request
|
||||||
|
|
||||||
|
**方向:** 服务端 → 客户端
|
||||||
|
|
||||||
|
**说明:** 好友申请推送
|
||||||
|
|
||||||
|
**data 内容:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"friendship_id": 5,
|
||||||
|
"from_user_id": 2,
|
||||||
|
"from_nickname": "李四",
|
||||||
|
"from_avatar": "https://...",
|
||||||
|
"message": "我是你的同事"
|
||||||
|
}
|
||||||
|
```
|
||||||
247
docs/architecture/system-architecture.md
Normal file
247
docs/architecture/system-architecture.md
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
# EchoChat 系统架构设计
|
||||||
|
|
||||||
|
> 本文档从整体设计方案中提取并深化架构设计部分,便于独立查阅。
|
||||||
|
> 完整设计方案见 `docs/plans/2026-02-27-echochat-system-design.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、架构概述
|
||||||
|
|
||||||
|
EchoChat 采用 **「精简单体 + 媒体微服务」** 架构,核心思想是 **控制面与媒体面彻底分离、业务系统与实时系统解耦**。
|
||||||
|
|
||||||
|
- **Go 单体服务**:处理所有业务逻辑(认证、IM、会议控制、好友、通知、后台管理),内部按模块化组织,保留后期拆分为微服务的能力
|
||||||
|
- **mediasoup Node 服务**:独立的媒体控制微服务,管理 SFU Worker,不涉及任何业务逻辑
|
||||||
|
- **mediasoup Worker**:C++ SFU 引擎,负责 RTP 转发、拥塞控制、带宽自适应
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、架构分层图
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 接入层 (Nginx) │
|
||||||
|
│ SSL 终止 · 反向代理 · WebSocket 升级 · 静态资源 · 负载均衡 │
|
||||||
|
└─────┬───────────────────────┬───────────────────────────────┘
|
||||||
|
│ │
|
||||||
|
│ HTTPS / WSS │ HTTPS
|
||||||
|
│ │
|
||||||
|
┌─────┴──────────┐ ┌──────┴──────────┐
|
||||||
|
│ 前台用户端 │ │ 后台管理端 │
|
||||||
|
│ uniapp │ │ Vue3+Element │
|
||||||
|
│ (H5/App/小程序)│ │ Plus (PC Web) │
|
||||||
|
└─────┬──────────┘ └──────┬──────────┘
|
||||||
|
│ │
|
||||||
|
│ WebSocket + HTTP │ HTTP (RESTful)
|
||||||
|
│ │
|
||||||
|
┌─────┴───────────────────────┴──────────────────────────────┐
|
||||||
|
│ Go 单体服务(模块化) │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
||||||
|
│ │ auth │ │ im │ │ meeting │ │ admin │ │
|
||||||
|
│ │ 认证鉴权 │ │ 即时通讯 │ │ 会议控制 │ │ 后台管理 │ │
|
||||||
|
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ contact │ │ notify │ 每个模块: Controller → │
|
||||||
|
│ │ 联系人 │ │ 通知 │ Service → DAO → Model │
|
||||||
|
│ └──────────┘ └──────────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ┌────┴──────────────┴──────────────┴──────┐ │
|
||||||
|
│ │ 公共基础设施层 (pkg/) │ │
|
||||||
|
│ │ db · redis · ws · middleware · utils │ │
|
||||||
|
│ └─────────────────────────────────────────┘ │
|
||||||
|
└────────┬──────────────────────┬─────────────────────────────┘
|
||||||
|
│ │
|
||||||
|
PostgreSQL Redis HTTP
|
||||||
|
(持久化数据) (实时状态) │
|
||||||
|
┌─────┴─────────────┐
|
||||||
|
│ mediasoup Node 服务 │
|
||||||
|
│ Router 管理 │
|
||||||
|
│ Transport 管理 │
|
||||||
|
│ Producer/Consumer │
|
||||||
|
└─────┬─────────────┘
|
||||||
|
│ IPC
|
||||||
|
┌─────┴─────────────┐
|
||||||
|
│ mediasoup Worker │
|
||||||
|
│ (C++ SFU 引擎) │
|
||||||
|
│ RTP 转发 │
|
||||||
|
│ 拥塞控制 │
|
||||||
|
│ 带宽自适应 │
|
||||||
|
└───────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、各层职责说明
|
||||||
|
|
||||||
|
### 3.1 接入层 (Nginx)
|
||||||
|
|
||||||
|
| 职责 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| SSL 终止 | 处理 HTTPS/WSS 加密,内部服务间通信使用 HTTP |
|
||||||
|
| 反向代理 | 将请求分发到 Go 服务或前端静态资源 |
|
||||||
|
| WebSocket 升级 | 处理 WebSocket 协议升级 |
|
||||||
|
| 负载均衡 | 后期多实例部署时进行请求分发 |
|
||||||
|
|
||||||
|
### 3.2 Go 单体服务
|
||||||
|
|
||||||
|
系统的 **"大脑"**,处理所有业务逻辑。
|
||||||
|
|
||||||
|
| 模块 | 职责 |
|
||||||
|
|------|------|
|
||||||
|
| auth | 用户注册/登录、JWT Token 管理、RBAC 角色权限 |
|
||||||
|
| im | 即时消息收发、会话管理、消息存储 |
|
||||||
|
| contact | 好友关系管理、好友分组 |
|
||||||
|
| meeting | 会议创建/管理、信令转发、mediasoup 资源编排 |
|
||||||
|
| notify | 通知推送、会议邀请、好友申请通知 |
|
||||||
|
| admin | 后台管理(用户管理、会议监控、系统配置) |
|
||||||
|
|
||||||
|
**不负责的事情:** 不处理 RTP 媒体数据、不参与音视频转发、不做 WebRTC 协议协商。
|
||||||
|
|
||||||
|
### 3.3 mediasoup Node 服务
|
||||||
|
|
||||||
|
mediasoup C++ SFU 的 **"遥控器"**,不懂业务、不懂用户、只懂媒体对象。
|
||||||
|
|
||||||
|
| 职责 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| Worker 管理 | 创建和管理 mediasoup C++ Worker 进程 |
|
||||||
|
| Router 管理 | 每个会议房间对应一个 Router |
|
||||||
|
| Transport 管理 | 为每个参与者创建 WebRTC Transport |
|
||||||
|
| Producer/Consumer | 管理音视频流的推送和消费 |
|
||||||
|
|
||||||
|
### 3.4 mediasoup Worker
|
||||||
|
|
||||||
|
真正的 **"发动机"**,纯 C++ 实现的 SFU 引擎。
|
||||||
|
|
||||||
|
| 职责 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| RTP 转发 | 接收发送者的 RTP 包,转发给所有接收者 |
|
||||||
|
| 拥塞控制 | 根据网络状况动态调整 |
|
||||||
|
| 带宽自适应 | Simulcast/SVC 支持 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、数据流说明
|
||||||
|
|
||||||
|
### 4.1 即时消息流
|
||||||
|
|
||||||
|
```
|
||||||
|
客户端A Go 服务 客户端B
|
||||||
|
│ │ │
|
||||||
|
│── WS: 发送消息 ──→ │ │
|
||||||
|
│ │── 写入 PostgreSQL │
|
||||||
|
│ │── 更新 Redis 未读数 │
|
||||||
|
│ ←── WS: 发送确认 ──│ │
|
||||||
|
│ │── WS: 推送新消息 ────────→ │
|
||||||
|
│ │ │
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 音视频会议流
|
||||||
|
|
||||||
|
```
|
||||||
|
客户端 Go 服务 mediasoup Node Worker
|
||||||
|
│ │ │ │
|
||||||
|
│── HTTP: 加入会议 → │ │ │
|
||||||
|
│ │── HTTP: 创建Router→│ │
|
||||||
|
│ │ ←── RTP能力 ──────│ │
|
||||||
|
│ ←── WS: 房间信息 ──│ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│── WS: 创建Transport→│ │ │
|
||||||
|
│ │── HTTP: 创建 ────→ │── IPC ──────→ │
|
||||||
|
│ ←── WS: Transport参数│ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│── WS: 开始推流 ──→ │ │ │
|
||||||
|
│ │── HTTP: Producer → │── IPC ──────→ │
|
||||||
|
│ │ │ │
|
||||||
|
│════════════════ RTP/DTLS 媒体流直连 ═══════════════════→│
|
||||||
|
│ (音视频数据不经过 Go 服务,直连 Worker) │
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、微服务演进路径
|
||||||
|
|
||||||
|
当前架构从第一天起就为微服务拆分做了准备:
|
||||||
|
|
||||||
|
### 5.1 代码层面的预留
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 模块间零直接引用 | `auth` 不会 import `im` 内部代码,通过 interface 通信 |
|
||||||
|
| 独立路由注册 | 每个模块有自己的 `router.go`,注册独立的路由组 |
|
||||||
|
| 数据库表按模块前缀 | `auth_users`、`im_messages`、`meeting_rooms`,后期可分库 |
|
||||||
|
| Redis key 按命名空间 | `echo:auth:*`、`echo:im:*`、`echo:meeting:*` |
|
||||||
|
|
||||||
|
### 5.2 演进路径
|
||||||
|
|
||||||
|
```
|
||||||
|
第一阶段(当前) 第二阶段 第三阶段
|
||||||
|
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||||
|
│ Go 单体服务 │ → │ Go 实时服务 │ → │ auth-service │
|
||||||
|
│ (模块化) │ │ (信令+会议+IM) │ │ im-service │
|
||||||
|
│ │ │ │ │ meeting-service │
|
||||||
|
│ │ │ Go 业务服务 │ │ contact-service │
|
||||||
|
│ │ │ (用户+好友+管理) │ │ admin-service │
|
||||||
|
└─────────────┘ └──────────────────┘ └─────────────────┘
|
||||||
|
+ API Gateway
|
||||||
|
+ 服务发现
|
||||||
|
+ 链路追踪
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、部署架构
|
||||||
|
|
||||||
|
### 6.1 开发环境 (Docker Compose)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
go-service: # Go 后端 → :8080
|
||||||
|
media-server: # mediasoup Node → :3000 + :40000-40100/udp
|
||||||
|
postgres: # PostgreSQL 16 → :5432
|
||||||
|
redis: # Redis 7 → :6379
|
||||||
|
nginx: # 反向代理 → :80/:443
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 生产环境 (预留 K8s)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ Kubernetes 集群 │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ │
|
||||||
|
│ │ Go Pod │ │ Go Pod │ (水平扩展) │
|
||||||
|
│ │ (副本1) │ │ (副本N) │ │
|
||||||
|
│ └────┬────┘ └────┬────┘ │
|
||||||
|
│ └──────┬─────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌───────────┴───────────┐ │
|
||||||
|
│ │ Service (LB) │ │
|
||||||
|
│ └───────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ mediasoup │ │ mediasoup │ │
|
||||||
|
│ │ Pod (副本1) │ │ Pod (副本N) │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ PostgreSQL (StatefulSet / 外部 RDS) │
|
||||||
|
│ Redis (StatefulSet / 外部 ElastiCache) │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、技术选型依据
|
||||||
|
|
||||||
|
| 技术 | 选型理由 |
|
||||||
|
|------|---------|
|
||||||
|
| **Go (Gin)** | 高并发、静态编译、内存占用小,适合实时系统 |
|
||||||
|
| **GORM** | Go 生态最成熟的 ORM,社区活跃 |
|
||||||
|
| **Wire** | 编译时依赖注入,零运行时开销 |
|
||||||
|
| **zap** | 高性能结构化日志,Uber 出品 |
|
||||||
|
| **Viper** | 配置管理标准库,支持 YAML + 环境变量覆盖 |
|
||||||
|
| **mediasoup** | 最高性能的开源 SFU,C++ 实现 |
|
||||||
|
| **PostgreSQL 16** | 强一致性、JSONB 支持、性能优异 |
|
||||||
|
| **Redis 7** | 实时状态存储、发布订阅、高速缓存 |
|
||||||
|
| **uniapp (Vue 3)** | 一套代码多端运行(H5/App/小程序) |
|
||||||
|
| **Element Plus** | Vue 3 生态最成熟的 PC 端组件库 |
|
||||||
|
| **Docker Compose** | 轻量级容器编排,适合初期和开发环境 |
|
||||||
@@ -187,9 +187,15 @@ EchoChat/
|
|||||||
|
|
||||||
### 4.1 PostgreSQL 核心表
|
### 4.1 PostgreSQL 核心表
|
||||||
|
|
||||||
|
> 所有表和字段均添加 `COMMENT` 注释,枚举类字段详细标注各值含义。
|
||||||
|
|
||||||
#### auth 模块 — 用户与权限
|
#### auth 模块 — 用户与权限
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- ============================================================
|
||||||
|
-- auth_users: 用户主表
|
||||||
|
-- 存储系统所有用户(包括普通用户和管理员),通过角色表区分权限
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE auth_users (
|
CREATE TABLE auth_users (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
username VARCHAR(50) UNIQUE NOT NULL,
|
username VARCHAR(50) UNIQUE NOT NULL,
|
||||||
@@ -197,46 +203,105 @@ CREATE TABLE auth_users (
|
|||||||
password_hash VARCHAR(255) NOT NULL,
|
password_hash VARCHAR(255) NOT NULL,
|
||||||
nickname VARCHAR(50) NOT NULL DEFAULT '',
|
nickname VARCHAR(50) NOT NULL DEFAULT '',
|
||||||
avatar VARCHAR(500) NOT NULL DEFAULT '',
|
avatar VARCHAR(500) NOT NULL DEFAULT '',
|
||||||
gender SMALLINT NOT NULL DEFAULT 0, -- 0:未知 1:男 2:女
|
gender SMALLINT NOT NULL DEFAULT 0,
|
||||||
phone VARCHAR(20) DEFAULT NULL,
|
phone VARCHAR(20) DEFAULT NULL,
|
||||||
status SMALLINT NOT NULL DEFAULT 1, -- 1:正常 2:禁用 3:注销
|
status SMALLINT NOT NULL DEFAULT 1,
|
||||||
last_login_at TIMESTAMPTZ DEFAULT NULL,
|
last_login_at TIMESTAMPTZ DEFAULT NULL,
|
||||||
last_login_ip VARCHAR(50) DEFAULT NULL,
|
last_login_ip VARCHAR(50) DEFAULT NULL,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE auth_users IS '用户主表,存储所有用户信息(普通用户与管理员共用)';
|
||||||
|
COMMENT ON COLUMN auth_users.id IS '用户唯一标识,自增主键';
|
||||||
|
COMMENT ON COLUMN auth_users.username IS '用户名,全局唯一,用于登录';
|
||||||
|
COMMENT ON COLUMN auth_users.email IS '邮箱地址,全局唯一,用于登录和通知';
|
||||||
|
COMMENT ON COLUMN auth_users.password_hash IS '密码哈希值,使用 bcrypt 加密存储';
|
||||||
|
COMMENT ON COLUMN auth_users.nickname IS '用户昵称,用于前端显示';
|
||||||
|
COMMENT ON COLUMN auth_users.avatar IS '头像 URL 地址';
|
||||||
|
COMMENT ON COLUMN auth_users.gender IS '性别:0=未知,1=男,2=女';
|
||||||
|
COMMENT ON COLUMN auth_users.phone IS '手机号码,可选';
|
||||||
|
COMMENT ON COLUMN auth_users.status IS '账号状态:1=正常,2=禁用(管理员封禁),3=注销(用户主动注销)';
|
||||||
|
COMMENT ON COLUMN auth_users.last_login_at IS '最后一次登录时间';
|
||||||
|
COMMENT ON COLUMN auth_users.last_login_ip IS '最后一次登录 IP 地址';
|
||||||
|
COMMENT ON COLUMN auth_users.created_at IS '账号创建时间';
|
||||||
|
COMMENT ON COLUMN auth_users.updated_at IS '信息最后更新时间';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- auth_roles: 角色表
|
||||||
|
-- 系统预置角色,用于 RBAC 权限控制
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE auth_roles (
|
CREATE TABLE auth_roles (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
code VARCHAR(50) UNIQUE NOT NULL, -- user, admin, super_admin
|
code VARCHAR(50) UNIQUE NOT NULL,
|
||||||
name VARCHAR(50) NOT NULL,
|
name VARCHAR(50) NOT NULL,
|
||||||
description VARCHAR(200) DEFAULT '',
|
description VARCHAR(200) DEFAULT '',
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE auth_roles IS '角色表,定义系统中所有角色类型';
|
||||||
|
COMMENT ON COLUMN auth_roles.id IS '角色唯一标识,自增主键';
|
||||||
|
COMMENT ON COLUMN auth_roles.code IS '角色代码,唯一标识:user=普通用户,admin=管理员,super_admin=超级管理员';
|
||||||
|
COMMENT ON COLUMN auth_roles.name IS '角色显示名称,如"普通用户""管理员""超级管理员"';
|
||||||
|
COMMENT ON COLUMN auth_roles.description IS '角色描述说明';
|
||||||
|
COMMENT ON COLUMN auth_roles.created_at IS '创建时间';
|
||||||
|
|
||||||
|
-- 预置角色数据
|
||||||
|
INSERT INTO auth_roles (code, name, description) VALUES
|
||||||
|
('user', '普通用户', '系统普通用户,可以使用聊天、会议等功能'),
|
||||||
|
('admin', '管理员', '后台管理员,可以管理用户、监控会议等'),
|
||||||
|
('super_admin', '超级管理员', '最高权限管理员,可以管理角色和系统配置');
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- auth_user_roles: 用户角色关联表
|
||||||
|
-- 多对多关系,一个用户可拥有多个角色
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE auth_user_roles (
|
CREATE TABLE auth_user_roles (
|
||||||
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
role_id INT NOT NULL REFERENCES auth_roles(id),
|
role_id INT NOT NULL REFERENCES auth_roles(id),
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
PRIMARY KEY (user_id, role_id)
|
PRIMARY KEY (user_id, role_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE auth_user_roles IS '用户角色关联表,建立用户与角色的多对多关系';
|
||||||
|
COMMENT ON COLUMN auth_user_roles.user_id IS '关联的用户 ID';
|
||||||
|
COMMENT ON COLUMN auth_user_roles.role_id IS '关联的角色 ID';
|
||||||
|
COMMENT ON COLUMN auth_user_roles.created_at IS '角色分配时间';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### contact 模块 — 联系人与好友
|
#### contact 模块 — 联系人与好友
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- ============================================================
|
||||||
|
-- contact_friendships: 好友关系表
|
||||||
|
-- 双向存储:A→B 和 B→A 各一条记录,便于查询"我的好友列表"
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE contact_friendships (
|
CREATE TABLE contact_friendships (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
friend_id BIGINT NOT NULL REFERENCES auth_users(id),
|
friend_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
remark VARCHAR(50) DEFAULT '',
|
remark VARCHAR(50) DEFAULT '',
|
||||||
group_id BIGINT DEFAULT NULL,
|
group_id BIGINT DEFAULT NULL,
|
||||||
status SMALLINT NOT NULL DEFAULT 0, -- 0:待确认 1:已接受 2:已拒绝 3:已拉黑
|
status SMALLINT NOT NULL DEFAULT 0,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
UNIQUE (user_id, friend_id)
|
UNIQUE (user_id, friend_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE contact_friendships IS '好友关系表,双向存储(A→B和B→A各一条记录)';
|
||||||
|
COMMENT ON COLUMN contact_friendships.id IS '记录唯一标识';
|
||||||
|
COMMENT ON COLUMN contact_friendships.user_id IS '发起方用户 ID';
|
||||||
|
COMMENT ON COLUMN contact_friendships.friend_id IS '好友用户 ID';
|
||||||
|
COMMENT ON COLUMN contact_friendships.remark IS '好友备注名,仅对当前用户可见';
|
||||||
|
COMMENT ON COLUMN contact_friendships.group_id IS '所属好友分组 ID,关联 contact_groups 表';
|
||||||
|
COMMENT ON COLUMN contact_friendships.status IS '好友关系状态:0=待确认(已发送申请),1=已接受(互为好友),2=已拒绝,3=已拉黑';
|
||||||
|
COMMENT ON COLUMN contact_friendships.created_at IS '记录创建时间(申请发送时间)';
|
||||||
|
COMMENT ON COLUMN contact_friendships.updated_at IS '最后更新时间(状态变更时间)';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- contact_groups: 好友分组表
|
||||||
|
-- 每个用户可自定义好友分组
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE contact_groups (
|
CREATE TABLE contact_groups (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
@@ -244,6 +309,13 @@ CREATE TABLE contact_groups (
|
|||||||
sort_order INT NOT NULL DEFAULT 0,
|
sort_order INT NOT NULL DEFAULT 0,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE contact_groups IS '好友分组表,用户可自定义分组管理好友';
|
||||||
|
COMMENT ON COLUMN contact_groups.id IS '分组唯一标识';
|
||||||
|
COMMENT ON COLUMN contact_groups.user_id IS '所属用户 ID';
|
||||||
|
COMMENT ON COLUMN contact_groups.name IS '分组名称,如"同事""家人""朋友"等';
|
||||||
|
COMMENT ON COLUMN contact_groups.sort_order IS '排序权重,数值越小越靠前';
|
||||||
|
COMMENT ON COLUMN contact_groups.created_at IS '创建时间';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### im 模块 — 即时通讯(统一会话模型)
|
#### im 模块 — 即时通讯(统一会话模型)
|
||||||
@@ -251,23 +323,42 @@ CREATE TABLE contact_groups (
|
|||||||
单聊和群聊统一抽象为"会话",本质都是"一组人在一个空间里收发消息"。这是微信、钉钉、Slack 等主流 IM 的标准模型。
|
单聊和群聊统一抽象为"会话",本质都是"一组人在一个空间里收发消息"。这是微信、钉钉、Slack 等主流 IM 的标准模型。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- ============================================================
|
||||||
|
-- im_conversations: 会话表
|
||||||
|
-- 统一抽象单聊和群聊,单聊时 name/avatar 为空(前端用对方信息展示)
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE im_conversations (
|
CREATE TABLE im_conversations (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
type SMALLINT NOT NULL, -- 1:单聊 2:群聊
|
type SMALLINT NOT NULL,
|
||||||
name VARCHAR(100) DEFAULT '',
|
name VARCHAR(100) DEFAULT '',
|
||||||
avatar VARCHAR(500) DEFAULT '',
|
avatar VARCHAR(500) DEFAULT '',
|
||||||
owner_id BIGINT DEFAULT NULL,
|
owner_id BIGINT DEFAULT NULL,
|
||||||
max_members INT NOT NULL DEFAULT 200,
|
max_members INT NOT NULL DEFAULT 200,
|
||||||
status SMALLINT NOT NULL DEFAULT 1, -- 1:正常 2:已解散
|
status SMALLINT NOT NULL DEFAULT 1,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE im_conversations IS '会话表,统一管理单聊和群聊会话';
|
||||||
|
COMMENT ON COLUMN im_conversations.id IS '会话唯一标识';
|
||||||
|
COMMENT ON COLUMN im_conversations.type IS '会话类型:1=单聊(两人私聊),2=群聊(多人群组)';
|
||||||
|
COMMENT ON COLUMN im_conversations.name IS '会话名称,群聊时为群名,单聊时为空(前端取对方昵称展示)';
|
||||||
|
COMMENT ON COLUMN im_conversations.avatar IS '会话头像 URL,群聊时为群头像,单聊时为空(前端取对方头像展示)';
|
||||||
|
COMMENT ON COLUMN im_conversations.owner_id IS '群主用户 ID,仅群聊时有值,单聊时为 NULL';
|
||||||
|
COMMENT ON COLUMN im_conversations.max_members IS '最大成员数,单聊固定为2,群聊默认200';
|
||||||
|
COMMENT ON COLUMN im_conversations.status IS '会话状态:1=正常,2=已解散(仅群聊可解散)';
|
||||||
|
COMMENT ON COLUMN im_conversations.created_at IS '会话创建时间';
|
||||||
|
COMMENT ON COLUMN im_conversations.updated_at IS '最后更新时间';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- im_conversation_members: 会话成员表
|
||||||
|
-- 记录每个会话中的参与成员及其个性化设置
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE im_conversation_members (
|
CREATE TABLE im_conversation_members (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
conversation_id BIGINT NOT NULL REFERENCES im_conversations(id),
|
conversation_id BIGINT NOT NULL REFERENCES im_conversations(id),
|
||||||
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
role SMALLINT NOT NULL DEFAULT 0, -- 0:普通成员 1:管理员 2:群主
|
role SMALLINT NOT NULL DEFAULT 0,
|
||||||
nickname VARCHAR(50) DEFAULT '',
|
nickname VARCHAR(50) DEFAULT '',
|
||||||
is_muted BOOLEAN NOT NULL DEFAULT FALSE,
|
is_muted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
is_pinned BOOLEAN NOT NULL DEFAULT FALSE,
|
is_pinned BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
@@ -276,74 +367,154 @@ CREATE TABLE im_conversation_members (
|
|||||||
UNIQUE (conversation_id, user_id)
|
UNIQUE (conversation_id, user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE im_conversation_members IS '会话成员表,记录成员列表及每人的个性化设置';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.id IS '记录唯一标识';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.conversation_id IS '所属会话 ID';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.user_id IS '成员用户 ID';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.role IS '成员角色:0=普通成员,1=管理员(群聊可设置),2=群主';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.nickname IS '群内昵称,仅在该群聊中生效,为空则使用用户全局昵称';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.is_muted IS '是否被禁言:false=正常发言,true=已被禁言(仅管理员/群主可操作)';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.is_pinned IS '是否置顶该会话:false=不置顶,true=置顶(个人设置,不影响他人)';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.last_read_msg_id IS '最后已读消息 ID,用于计算未读消息数';
|
||||||
|
COMMENT ON COLUMN im_conversation_members.joined_at IS '加入会话的时间';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- im_messages: 消息表
|
||||||
|
-- 系统数据量最大的表,存储所有聊天消息内容
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE im_messages (
|
CREATE TABLE im_messages (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
conversation_id BIGINT NOT NULL,
|
conversation_id BIGINT NOT NULL,
|
||||||
sender_id BIGINT NOT NULL,
|
sender_id BIGINT NOT NULL,
|
||||||
type SMALLINT NOT NULL DEFAULT 1, -- 1:文本 2:图片 3:文件 4:语音 5:系统消息
|
type SMALLINT NOT NULL DEFAULT 1,
|
||||||
content TEXT NOT NULL DEFAULT '',
|
content TEXT NOT NULL DEFAULT '',
|
||||||
extra JSONB DEFAULT '{}',
|
extra JSONB DEFAULT '{}',
|
||||||
status SMALLINT NOT NULL DEFAULT 1, -- 1:正常 2:已撤回 3:已删除
|
status SMALLINT NOT NULL DEFAULT 1,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE im_messages IS '聊天消息表,存储所有会话的消息记录(系统数据量最大的表)';
|
||||||
|
COMMENT ON COLUMN im_messages.id IS '消息唯一标识,全局自增';
|
||||||
|
COMMENT ON COLUMN im_messages.conversation_id IS '所属会话 ID';
|
||||||
|
COMMENT ON COLUMN im_messages.sender_id IS '发送者用户 ID';
|
||||||
|
COMMENT ON COLUMN im_messages.type IS '消息类型:1=文本消息,2=图片消息,3=文件消息,4=语音消息,5=系统通知消息';
|
||||||
|
COMMENT ON COLUMN im_messages.content IS '消息内容,文本消息为文字,其他类型为描述文字或为空';
|
||||||
|
COMMENT ON COLUMN im_messages.extra IS '附加数据(JSON),图片消息存 {url,width,height},文件消息存 {url,name,size},语音消息存 {url,duration}';
|
||||||
|
COMMENT ON COLUMN im_messages.status IS '消息状态:1=正常,2=已撤回(发送者撤回),3=已删除(管理员删除)';
|
||||||
|
COMMENT ON COLUMN im_messages.created_at IS '消息发送时间';
|
||||||
|
|
||||||
CREATE INDEX idx_im_messages_conv_time ON im_messages(conversation_id, created_at DESC);
|
CREATE INDEX idx_im_messages_conv_time ON im_messages(conversation_id, created_at DESC);
|
||||||
|
COMMENT ON INDEX idx_im_messages_conv_time IS '会话消息时间索引,用于按时间倒序查询会话历史消息';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### meeting 模块 — 音视频会议
|
#### meeting 模块 — 音视频会议
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- ============================================================
|
||||||
|
-- meeting_rooms: 会议房间表
|
||||||
|
-- 存储所有会议信息,支持即时会议和预约会议两种类型
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE meeting_rooms (
|
CREATE TABLE meeting_rooms (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
room_code VARCHAR(20) UNIQUE NOT NULL, -- 会议号
|
room_code VARCHAR(20) UNIQUE NOT NULL,
|
||||||
title VARCHAR(200) NOT NULL,
|
title VARCHAR(200) NOT NULL,
|
||||||
host_id BIGINT NOT NULL REFERENCES auth_users(id),
|
host_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
type SMALLINT NOT NULL DEFAULT 1, -- 1:即时会议 2:预约会议
|
type SMALLINT NOT NULL DEFAULT 1,
|
||||||
password VARCHAR(50) DEFAULT NULL,
|
password VARCHAR(50) DEFAULT NULL,
|
||||||
max_members INT NOT NULL DEFAULT 50,
|
max_members INT NOT NULL DEFAULT 50,
|
||||||
status SMALLINT NOT NULL DEFAULT 0, -- 0:未开始 1:进行中 2:已结束
|
status SMALLINT NOT NULL DEFAULT 0,
|
||||||
scheduled_at TIMESTAMPTZ DEFAULT NULL, -- 预约时间(即时会议为NULL)
|
scheduled_at TIMESTAMPTZ DEFAULT NULL,
|
||||||
started_at TIMESTAMPTZ DEFAULT NULL,
|
started_at TIMESTAMPTZ DEFAULT NULL,
|
||||||
ended_at TIMESTAMPTZ DEFAULT NULL,
|
ended_at TIMESTAMPTZ DEFAULT NULL,
|
||||||
settings JSONB DEFAULT '{}', -- 会议设置
|
settings JSONB DEFAULT '{}',
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE meeting_rooms IS '会议房间表,存储所有会议的基本信息和状态';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.id IS '会议唯一标识,自增主键';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.room_code IS '会议号(用户可见),如"123-456-789",用于分享和加入会议';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.title IS '会议标题';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.host_id IS '会议创建者/主持人用户 ID';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.type IS '会议类型:1=即时会议(立即创建立即开始),2=预约会议(设定未来时间)';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.password IS '会议密码,NULL 表示无密码,任何人可直接加入';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.max_members IS '最大参会人数,默认50人';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.status IS '会议状态:0=未开始(仅预约会议),1=进行中,2=已结束';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.scheduled_at IS '预约时间,仅预约会议有值,即时会议为 NULL';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.started_at IS '实际开始时间';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.ended_at IS '实际结束时间';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.settings IS '会议设置(JSON),如 {mute_on_join: true, allow_recording: false, auto_start: true}';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.created_at IS '会议创建时间';
|
||||||
|
COMMENT ON COLUMN meeting_rooms.updated_at IS '信息最后更新时间';
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- meeting_participants: 会议参与者表
|
||||||
|
-- 记录每场会议的参与者及其参会信息
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE meeting_participants (
|
CREATE TABLE meeting_participants (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
room_id BIGINT NOT NULL REFERENCES meeting_rooms(id),
|
room_id BIGINT NOT NULL REFERENCES meeting_rooms(id),
|
||||||
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
role SMALLINT NOT NULL DEFAULT 0, -- 0:参与者 1:主持人 2:联合主持人
|
role SMALLINT NOT NULL DEFAULT 0,
|
||||||
joined_at TIMESTAMPTZ DEFAULT NULL,
|
joined_at TIMESTAMPTZ DEFAULT NULL,
|
||||||
left_at TIMESTAMPTZ DEFAULT NULL,
|
left_at TIMESTAMPTZ DEFAULT NULL,
|
||||||
duration INT DEFAULT 0,
|
duration INT DEFAULT 0,
|
||||||
UNIQUE (room_id, user_id)
|
UNIQUE (room_id, user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE meeting_participants IS '会议参与者表,记录每场会议的所有参与者信息';
|
||||||
|
COMMENT ON COLUMN meeting_participants.id IS '记录唯一标识';
|
||||||
|
COMMENT ON COLUMN meeting_participants.room_id IS '所属会议 ID';
|
||||||
|
COMMENT ON COLUMN meeting_participants.user_id IS '参与者用户 ID';
|
||||||
|
COMMENT ON COLUMN meeting_participants.role IS '参会角色:0=普通参与者,1=主持人(会议创建者),2=联合主持人(主持人指定)';
|
||||||
|
COMMENT ON COLUMN meeting_participants.joined_at IS '加入会议的时间';
|
||||||
|
COMMENT ON COLUMN meeting_participants.left_at IS '离开会议的时间,NULL 表示仍在会议中';
|
||||||
|
COMMENT ON COLUMN meeting_participants.duration IS '累计参会时长(秒),离开时自动计算';
|
||||||
```
|
```
|
||||||
|
|
||||||
会议类型状态流转:
|
会议类型状态流转:
|
||||||
- 即时会议:创建 → 进行中(1) → 已结束(2)
|
- **即时会议**(type=1):创建 → 进行中(status=1) → 已结束(status=2)
|
||||||
- 预约会议:创建 → 未开始(0) → 进行中(1) → 已结束(2)
|
- **预约会议**(type=2):创建 → 未开始(status=0) → 进行中(status=1) → 已结束(status=2)
|
||||||
|
|
||||||
#### notify 模块 — 消息通知
|
#### notify 模块 — 消息通知
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- ============================================================
|
||||||
|
-- notify_notifications: 通知表
|
||||||
|
-- 存储所有推送给用户的通知消息
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE notify_notifications (
|
CREATE TABLE notify_notifications (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
type VARCHAR(50) NOT NULL, -- meeting_invite, friend_request, system
|
type VARCHAR(50) NOT NULL,
|
||||||
title VARCHAR(200) NOT NULL,
|
title VARCHAR(200) NOT NULL,
|
||||||
content TEXT DEFAULT '',
|
content TEXT DEFAULT '',
|
||||||
extra JSONB DEFAULT '{}',
|
extra JSONB DEFAULT '{}',
|
||||||
is_read BOOLEAN NOT NULL DEFAULT FALSE,
|
is_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE notify_notifications IS '通知消息表,存储推送给用户的所有类型通知';
|
||||||
|
COMMENT ON COLUMN notify_notifications.id IS '通知唯一标识';
|
||||||
|
COMMENT ON COLUMN notify_notifications.user_id IS '接收通知的用户 ID';
|
||||||
|
COMMENT ON COLUMN notify_notifications.type IS '通知类型:meeting_invite=会议邀请,friend_request=好友申请,friend_accepted=好友已接受,meeting_reminder=会议提醒,system=系统通知';
|
||||||
|
COMMENT ON COLUMN notify_notifications.title IS '通知标题';
|
||||||
|
COMMENT ON COLUMN notify_notifications.content IS '通知正文内容';
|
||||||
|
COMMENT ON COLUMN notify_notifications.extra IS '附加数据(JSON),如会议邀请存 {room_code, room_title},好友申请存 {from_user_id, from_username}';
|
||||||
|
COMMENT ON COLUMN notify_notifications.is_read IS '是否已读:false=未读,true=已读';
|
||||||
|
COMMENT ON COLUMN notify_notifications.created_at IS '通知创建时间';
|
||||||
|
|
||||||
CREATE INDEX idx_notify_user_read ON notify_notifications(user_id, is_read, created_at DESC);
|
CREATE INDEX idx_notify_user_read ON notify_notifications(user_id, is_read, created_at DESC);
|
||||||
|
COMMENT ON INDEX idx_notify_user_read IS '用户未读通知索引,优化"获取未读通知列表"查询';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### admin 模块 — 管理操作日志
|
#### admin 模块 — 管理操作日志
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- ============================================================
|
||||||
|
-- admin_operation_logs: 管理操作日志表
|
||||||
|
-- 记录后台管理员的所有操作行为,用于审计和追踪
|
||||||
|
-- ============================================================
|
||||||
CREATE TABLE admin_operation_logs (
|
CREATE TABLE admin_operation_logs (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
admin_id BIGINT NOT NULL REFERENCES auth_users(id),
|
admin_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
@@ -355,6 +526,17 @@ CREATE TABLE admin_operation_logs (
|
|||||||
ip VARCHAR(50) DEFAULT '',
|
ip VARCHAR(50) DEFAULT '',
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE admin_operation_logs IS '管理操作日志表,记录所有后台管理员的操作行为';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.id IS '日志唯一标识';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.admin_id IS '操作管理员的用户 ID';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.module IS '操作所属模块:user=用户管理,meeting=会议管理,permission=权限管理,system=系统配置';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.action IS '操作类型:create=创建,update=修改,delete=删除,disable=禁用,enable=启用,close=关闭';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.target_type IS '操作目标类型:user=用户,meeting=会议,role=角色,config=配置';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.target_id IS '操作目标 ID,关联对应表的主键';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.detail IS '操作详情(JSON),如 {before: {...}, after: {...}} 记录变更前后数据';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.ip IS '操作者 IP 地址';
|
||||||
|
COMMENT ON COLUMN admin_operation_logs.created_at IS '操作时间';
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.2 Redis 数据结构
|
### 4.2 Redis 数据结构
|
||||||
|
|||||||
Reference in New Issue
Block a user