Files
danyang-match/实时聊天、消息通知与反骚扰机制详细设计.md
T

3145 lines
39 KiB
Markdown
Raw Normal View History

2026-09-09 22:05:00 +08:00
# 丹阳公益婚恋服务平台
# V1.0 实时聊天、消息通知与反骚扰机制详细设计
版本:V1.0
适用范围:微信小程序用户端、公益红娘工作台、运营管理后台
核心目标:只在双方明确同意后建立沟通、保证消息稳定送达、降低骚扰与诈骗风险、保护聊天隐私、确保拉黑/封禁即时生效
---
# 第一章 设计目标
V1.0聊天模块不是社交娱乐平台。
它只服务于一个明确场景:
> 双方互相喜欢以后,提供安全、简单、可靠的进一步沟通渠道。
因此V1.0聊天设计必须坚持:
- 双向喜欢后才能聊天
- 不支持陌生人私信
- 不支持群聊
- 不支持红包
- 不支持转账
- 不支持直播
- 不支持语音房
- 不支持“超级消息”
- 不允许付费解锁聊天
- 拉黑后立即停止通信
- 风控状态变化立即影响聊天权限
- 工作人员默认无权查看私人聊天
---
# 第二章 V1聊天功能范围
支持:
```text
文字消息
图片消息
Emoji
系统消息
安全提醒
消息未读
已读同步
失败重试
历史记录分页
举报
拉黑
解除匹配
```
V1暂不支持:
```text
语音消息
实时语音通话
视频通话
位置共享
文件
名片
红包
转账
群聊
阅后即焚
朋友圈
```
---
# 第三章 聊天入口规则
用户A与用户B只有同时满足:
```text
存在有效Match
+
match.status = active / getting_to_know
+
双方账号可用
+
双方未拉黑
+
conversation.can_send = true
```
才允许聊天。
---
# 第四章 会话创建时机
推荐V1:
> 双向喜欢成功时立即创建Conversation。
流程:
```text
A喜欢B
↓
发现B已经喜欢A
↓
创建Match
↓
创建Conversation
↓
创建双方ConversationMember
↓
发送双向匹配通知
```
这样用户点击:
> 开始聊天
时不需要额外创建会话。
---
# 第五章 Conversation状态
V1只保留:
```text
active
closed
```
active:
> 可以聊天。
closed:
> 不能发送新消息。
---
# 第六章 Conversation关闭条件
以下任一情况发生:
```text
解除匹配
A拉黑B
B拉黑A
任一方账号封禁
任一方账号关闭
风控明确禁止聊天
```
Conversation立即:
```text
status = closed
```
双方成员:
```text
can_send = false
```
---
# 第七章 历史聊天是否删除
关闭Conversation以后:
> 不物理删除历史聊天。
原因:
- 用户自己仍可能需要查看历史
- 举报取证
- 风控调查
- 纠纷处理
但是否继续向用户展示历史,要根据场景决定。
---
# 第八章 解除匹配后的聊天
解除匹配后建议:
> 历史会话保留为只读。
页面顶部:
```text
你们已解除匹配,无法继续发送消息。
```
输入框:
> 禁用。
---
# 第九章 拉黑后的聊天
拉黑比解除匹配更强。
建议:
拉黑方:
> 不再看到对方正常会话入口,可在黑名单中管理。
被拉黑方:
> 不提示“你被谁拉黑了”。
只显示:
> 当前无法继续聊天。
防止引发冲突。
---
# 第十章 Conversation数据模型
建议:
```text
conversations
conversation_members
messages
```
核心字段沿用前面数据库设计。
---
# 第十一章 conversation_members
至少包含:
```text
conversation_id
user_id
last_read_message_id
unread_count
can_send
joined_at
```
未来即使一直是一对一聊天,也保留member结构。
---
# 第十二章 消息类型
V1:
```text
text
image
system
risk_notice
```
---
# 第十三章 Text消息结构
示例:
```json
{
"id": "msg_xxx",
"conversationId": "con_xxx",
"senderId": "usr_xxx",
"type": "text",
"content": "你好,很高兴认识你",
"createdAt": "2026-08-28T10:32:00+08:00",
"status": "sent"
}
```
---
# 第十四章 Image消息结构
```json
{
"id": "msg_xxx",
"conversationId": "con_xxx",
"senderId": "usr_xxx",
"type": "image",
"fileId": "file_xxx",
"thumbnailUrl": "...",
"imageUrl": "...",
"createdAt": "..."
}
```
图片URL:
> 必须为临时签名URL。
---
# 第十五章 System消息
由系统生成。
例如:
```text
你们互相喜欢,可以开始聊天了。
```
```text
你们已解除匹配。
```
```text
当前会话已停止发送消息。
```
System消息:
> 用户不能伪造。
sender_id可以为空,由message_type区分。
---
# 第十六章 RiskNotice
用于安全提示。
例如:
```text
安全提醒:婚恋交友过程中请谨慎涉及转账、借款、投资等资金往来。
```
RiskNotice不作为普通聊天内容的一方发言。
---
# 第十七章 WebSocket总体架构
推荐:
```text
微信小程序
│
│ HTTPS
↓
REST API
│
│
└────→ PostgreSQL
│
↓
WebSocket Gateway
│
↓
Redis
```
V1可以和主后端部署在同一个应用中。
不需要独立消息微服务。
---
# 第十八章 WebSocket连接地址
示例:
```text
wss://api.example.com/ws
```
必须:
> WSS。
生产不得使用:
```text
ws://
```
---
# 第十九章 WebSocket认证
建立连接时:
> 必须验证有效登录凭证。
禁止:
```text
userId=123
```
作为身份依据。
正确:
```text
Token
↓
服务端解析
↓
得到真正userId
↓
绑定connection
```
---
# 第二十章 Connection状态
前端统一:
```text
disconnected
connecting
connected
reconnecting
```
MessageStore统一管理。
---
# 第二十一章 WebSocket建立流程
```text
小程序进入前台
↓
检查Token
↓
建立WS
↓
Token认证
↓
Server绑定userId
↓
connected
↓
拉取遗漏消息
```
---
# 第二十二章 WebSocket断线重连
断线以后:
> 自动重连。
建议退避:
```text
1s
2s
5s
10s
20s
30s
```
最大:
> 30秒。
恢复后重置。
---
# 第二十三章 不要无限高频重连
如果:
- Token失效
- 账号封禁
- 网络完全离线
不能每秒持续重连。
对应:
```text
AUTH_EXPIRED
ACCOUNT_BANNED
OFFLINE
```
停止或降低重连。
---
# 第二十四章 微信小程序前后台切换
进入后台时:
WebSocket可能被系统暂停或断开。
重新回前台:
```text
检查连接
↓
必要时重连
↓
同步消息
↓
刷新未读数
```
---
# 第二十五章 心跳
WebSocket建议:
```text
客户端Ping
服务端Pong
```
间隔示例:
```text
30~60秒
```
具体根据实际微信小程序网络特性调整。
---
# 第二十六章 实时事件
建议:
```text
message.new
message.read
conversation.closed
match.created
notification.new
account.status_changed
```
---
# 第二十七章 message.new
示例:
```json
{
"event": "message.new",
"eventId": "evt_xxx",
"data": {
"conversationId": "con_xxx",
"message": {}
}
}
```
---
# 第二十八章 eventId
每个实时事件建议拥有:
```text
eventId
```
前端可用于:
> 去重。
避免断线恢复后重复消费。
---
# 第二十九章 消息发送方式
推荐V1:
> 消息发送走REST,实时接收走WebSocket。
即:
```text
POST /conversations/{id}/messages
```
成功后:
服务端推送WebSocket。
优点:
- 幂等更清晰
- API测试简单
- 弱网容易重试
- 权限处理统一
---
# 第三十章 为什么不建议V1全部走WebSocket发送
全WebSocket双向消息虽然可行,但会增加:
- ACK机制
- 重发协议
- 幂等实现
- 连接异常处理
- 测试复杂度
V1采用:
> REST发送 + WS接收
更简单可靠。
---
# 第三十一章 clientMessageId
每条客户端消息必须生成:
```text
clientMessageId
```
例如:
```text
cm_018...
```
服务端唯一:
```text
sender_id + client_message_id
```
---
# 第三十二章 消息发送流程
```text
用户输入
↓
本地生成clientMessageId
↓
UI显示sending
↓
POST消息
↓
服务端鉴权
↓
验证Conversation
↓
风险检测
↓
数据库保存
↓
返回正式messageId
↓
UI sent
↓
服务端WS推送给接收方
```
---
# 第三十三章 发送状态
前端:
```text
sending
sent
failed
```
---
# 第三十四章 Sending视觉
发送过程中:
> 不需要大Loading。
可使用:
> 小型旋转图标或灰色状态。
---
# 第三十五章 Failed视觉
失败:
```text
!
```
点击:
> 重新发送。
必须使用原:
```text
clientMessageId
```
保证不会重复。
---
# 第三十六章 服务端成功但客户端超时
典型弱网:
```text
Server保存成功
↓
Response在网络中丢失
↓
客户端显示failed
↓
用户重试
```
由于clientMessageId相同:
服务端返回:
> 原消息。
不会插入第二条。
---
# 第三十七章 消息排序
服务端以:
```text
created_at
+
message_id
```
稳定排序。
不要完全相信客户端时间。
---
# 第三十八章 客户端时间用途
客户端时间只用于:
> 本地临时展示。
最终:
> 服务端createdAt为准。
---
# 第三十九章 历史消息加载
进入聊天:
首先加载最近:
```text
20~30条
```
向上滚动:
> 加载更早。
Cursor分页。
---
# 第四十章 消息Cursor
推荐使用:
```text
createdAt + messageId
```
或数据库生成稳定cursor。
避免传统:
```text
page=100
```
在实时消息变化下错乱。
---
# 第四十一章 本地聊天缓存
可以缓存:
> 最近少量消息。
用于:
- 快速打开
- 弱网显示
但长期历史仍从服务端获取。
---
# 第四十二章 不在Storage长期保存全部聊天
原因:
- 用户隐私
- 设备共享风险
- 数据量大
建议只保存:
> 必要的近期缓存。
并设置清理策略。
---
# 第四十三章 聊天输入草稿
本地:
```text
chatDraft[conversationId]
```
用户退出聊天:
> 保留未发送文字。
---
# 第四十四章 草稿不得同步给对方
当然只存在本地。
服务端不需要保存“正在输入内容”。
---
# 第四十五章 V1不做正在输入
不需要:
```text
对方正在输入...
```
减少实时协议复杂度。
---
# 第四十六章 已读机制
用户真正打开Conversation并读取消息后:
```text
POST /conversations/{id}/read
```
发送:
```text
lastReadMessageId
```
---
# 第四十七章 已读位置只向前
若当前:
```text
lastRead = msg100
```
旧请求晚到:
```text
msg90
```
服务器必须忽略。
不能回退到msg90。
---
# 第四十八章 V1是否显示“已读”
建议:
> V1不向发送者显示精确“已读”。
原因:
- 降低社交压力
- 减少焦虑
- 简化产品
后台仍可维护阅读位置用于未读统计。
---
# 第四十九章 未读数计算
MessageStore:
```text
chatUnreadCount
systemUnreadCount
totalUnreadCount
```
统一来源。
---
# 第五十章 新消息未读
当B不在当前Conversation:
A发消息:
```text
B.unread_count + 1
```
如果B当前正在该Conversation并已加载:
可以实时标记阅读。
---
# 第五十一章 Tab Badge
消息Tab:
```text
totalUnreadCount
```
超过99:
```text
99+
```
---
# 第五十二章 消息列表排序
按:
```text
last_message_at DESC
```
最近聊天在最上。
---
# 第五十三章 消息列表项
展示:
- 头像
- 展示名
- 最近消息摘要
- 时间
- 未读数量
---
# 第五十四章 图片消息摘要
聊天列表:
```text
[图片]
```
不要尝试自动OCR图片内容作为摘要。
---
# 第五十五章 风险系统消息摘要
可显示:
```text
安全提醒
```
但不要让安全消息把真正用户消息列表全部顶掉。
---
# 第五十六章 System Notification与Chat分离
消息首页两个Tab:
```text
聊天
系统通知
```
业务通知不塞进普通聊天列表。
---
# 第五十七章 系统通知分类
```text
审核通知
匹配通知
红娘通知
活动通知
安全通知
账号通知
系统通知
```
---
# 第五十八章 系统通知数据结构
建议:
```json
{
"id": "not_xxx",
"type": "activity",
"title": "活动报名已通过",
"content": "你报名的丹阳青年公益相亲会已通过审核。",
"businessType": "activity",
"businessId": "act_xxx",
"read": false,
"createdAt": "..."
}
```
---
# 第五十九章 通知点击跳转
根据:
```text
businessType
businessId
```
跳:
```text
review → 审核页
match → 我的缘分/聊天
activity → 活动详情
matchmaker → 红娘服务
risk → 账号状态
```
---
# 第六十章 通知不能传完整路由URL
后端不应任意下发:
```text
https://...
```
由前端根据:
> businessType
映射内部页面。
避免开放重定向。
---
# 第六十一章 通知去重
例如双向匹配事务重试。
不能生成多个:
> 你们互相喜欢。
唯一键可以:
```text
user_id
+
notification_type
+
business_id
```
---
# 第六十二章 通知状态
```text
unread
read
```
V1足够。
不需要:
- archived
- starred
- deleted
---
# 第六十三章 全部已读
提供:
```text
POST /notifications/read-all
```
用户可以快速清除Badge。
---
# 第六十四章 微信订阅消息的定位
微信订阅消息只用于:
> 重要站外提醒。
例如:
- 审核结果
- 活动提醒
- 红娘服务重要更新
不能用于:
> 每来一条聊天都发微信订阅消息。
---
# 第六十五章 新聊天是否外部提醒
V1建议:
如果用户不在小程序:
> 不依赖每条聊天外部推送。
可以后续提供:
> 有新的婚恋消息
聚合提醒。
具体须遵循微信订阅消息实际规则。
---
# 第六十六章 反骚扰体系总体模型
反骚扰不是只靠“举报”。
体系包括:
```text
聊天准入限制
+
发送频率限制
+
内容风险提醒
+
拉黑
+
举报
+
风险评分
+
人工处置
```
---
# 第六十七章 第一层:陌生人不能直接发消息
这是最重要的反骚扰规则。
因为:
> 没有双向喜欢,就没有聊天。
直接消除大量陌生私信骚扰。
---
# 第六十八章 第二层:发送频率限制
需要防:
- 刷屏
- 机器人
- 骚扰
建议配置:
```text
单会话短时间消息上限
单用户总发送速率
连续相同消息限制
```
---
# 第六十九章 不建议把正常聊天限得过死
例如:
正常用户快速连续发5句:
> 不应该被处罚。
限频主要拦:
> 极端异常速率。
---
# 第七十章 高频行为分级
例如:
```text
Level 1:
稍微高频
→ 不处理
Level 2:
明显高频
→ 轻限速
Level 3:
机器式高频
→ 临时停止发送 + RiskEvent
```
阈值配置化。
---
# 第七十一章 重复文本检测
如果用户向多个对象发送:
> 完全相同的营销话术。
可以记录:
```text
DUPLICATE_MESSAGE_SPAM
```
风险事件。
---
# 第七十二章 跨会话群发
例如同一用户:
```text
1分钟内
向10个不同Match
发送完全相同内容
```
非常值得关注。
系统:
- 风险加分
- 限速
- 人工关注
---
# 第七十三章 联系方式识别
聊天中可以允许用户:
> 自主交换联系方式。
所以不能像Profile一样完全禁止手机号和微信号。
但大量、高频向不同用户发送联系方式:
> 可能是引流/营销。
需要结合频率判断。
---
# 第七十四章 Profile与Chat的区别
Profile:
> 不允许放联系方式。
Chat:
> 双向Match后允许用户自主交流。
这是重要规则差异。
---
# 第七十五章 资金风险词
重点词组:
```text
转账
借钱
投资
理财
虚拟币
博彩
贷款
刷单
银行卡
高收益
项目投资
资金周转
```
命中:
> 风险提醒。
---
# 第七十六章 普通关键词提示
第一次风险命中:
系统插入:
```text
安全提醒:
婚恋交友过程中请谨慎涉及资金往来,
不要轻信投资、借款或高收益项目。
```
---
# 第七十七章 同一会话不要反复提示
例如用户正常聊银行工作。
不能每次出现“投资”都插一条黄色提醒。
建议:
```text
同类风险提示
24小时/一段会话内
最多提示1次
```
具体可配置。
---
# 第七十八章 风险提示冷却
例如:
```text
money_warning cooldown = 24h
```
这样避免干扰。
---
# 第七十九章 严重风险组合
单关键词不处罚。
但是组合行为:
```text
多用户举报诈骗
+
高频发送投资话术
+
多人拉黑
```
风险显著提高。
---
# 第八十章 风险评分不在聊天UI显示
不能告诉用户:
```text
对方风险分82
```
除非账号已经进入明确处置状态。
---
# 第八十一章 被多人拉黑
被多人拉黑:
> 是风险信号。
但也可能是正常婚恋拒绝。
所以权重不能过高。
结合:
- 举报
- 高频消息
- 重复话术
综合判断。
---
# 第八十二章 单会话举报入口
聊天右上角:
```text
···
```
包含:
```text
查看资料
解除匹配
举报
拉黑
```
---
# 第八十三章 举报聊天时的证据方式
用户可以:
> 直接选择举报当前用户。
系统自动关联:
```text
conversationId
```
并允许用户选择:
> 相关聊天时间范围/截图。
---
# 第八十四章 不建议让用户手工截所有聊天
如果用户举报:
平台内部已有Conversation。
可以让系统后台在授权调查时:
> 查询相关上下文。
用户可额外上传截图作为补充。
---
# 第八十五章 举报关联信息
Report可以记录:
```text
conversation_id
related_message_ids
```
这样风控查看更准确。
---
# 第八十六章 风控人员聊天访问
默认:
> 无权限。
处理举报时:
只有拥有:
```text
message.content.review
```
才能访问。
同时写:
> Sensitive Access Log。
---
# 第八十七章 红娘不能查看用户聊天
即使红娘负责双方用户:
> 也不能查看两人的私人聊天。
红娘只能根据用户主动反馈:
> “不知道怎么聊”
给一般建议。
---
# 第八十八章 红娘聊天辅助
用户申请:
> 不知道怎么开始聊天。
红娘可以:
- 给聊天建议
- 给破冰话题
- 根据公开资料建议话题
不能:
> 登录用户账号替他聊天。
---
# 第八十九章 V1不做AI代聊
不提供:
> AI自动替用户回复。
避免:
- 身份真实性问题
- 情感欺骗
- 误发内容
- 责任不清
---
# 第九十章 可以后续提供的辅助
未来最多考虑:
> 用户主动点击“帮我润色一句”。
且必须:
- 用户确认
- AI不自动发送
V1不做。
---
# 第九十一章 图片消息安全
用户聊天图片上传:
必须:
- 图片格式校验
- 大小校验
- EXIF清理
- 风险扫描
- 私有存储
---
# 第九十二章 图片消息审核策略
V1可以:
> 机器基础安全检测 + 举报后人工处理。
是否每张聊天图片人工预审:
> 不建议。
会严重影响隐私与成本。
---
# 第九十三章 明显非法图片
如果自动内容安全服务识别到:
> 高置信度违法/色情内容。
可以:
- 阻止发送
- 记录风险事件
- 必要时人工复核
---
# 第九十四章 图片失败
图片上传成功但消息发送失败:
文件成为:
> 未绑定临时对象。
定时任务清理。
---
# 第九十五章 上传图片大小
建议:
```text
原图 ≤ 10MB
```
后端:
> 压缩。
聊天展示不需要保存巨大原图。
---
# 第九十六章 图片预览
点击图片:
> 全屏预览。
禁止自动保存到相册。
如用户主动保存:
> 使用系统正常授权流程。
---
# 第九十七章 消息撤回
V1建议:
> 暂不做消息撤回。
原因:
- 增加状态复杂度
- 举报取证更复杂
- 不是核心需求
---
# 第九十八章 删除聊天
V1可以不提供:
> 删除整个Conversation。
如果未来提供:
只做:
> 用户侧隐藏
而不是物理删除系统记录。
---
# 第九十九章 敏感词与内容过滤
区分:
```text
非法内容
风险内容
普通敏感场景
```
非法内容:
> 阻止。
风险内容:
> 提醒或进入风控。
普通敏感场景:
> 正常允许。
---
# 第一百章 不要建立超大关键词黑名单
维护成本高,误伤严重。
V1重点:
> 小而明确的反诈骗/违法规则集。
---
# 第一百零一章 安全规则配置
后台可维护:
```text
消息发送频率阈值
重复文本阈值
风险关键词
风险提示冷却
高风险分数阈值
```
但修改必须:
> Audit。
---
# 第一百零二章 规则配置不要让普通运营改
权限:
```text
risk.rule.manage
```
仅安全管理员。
---
# 第一百零三章 用户主动拉黑流程
```text
点击拉黑
↓
二次确认
↓
POST block
↓
建立blocked关系
↓
Match失效/聊天关闭
↓
更新缓存
↓
WS通知相关客户端状态变化
```
---
# 第一百零四章 拉黑确认文案
建议:
```text
拉黑后,对方将无法继续与你聊天,
你们也不会再互相出现在推荐中。
确认拉黑?
```
按钮:
```text
确认拉黑
取消
```
---
# 第一百零五章 被拉黑方通知
不要发送:
> “王女士拉黑了你。”
这样可能引发线下冲突。
只在其尝试访问Conversation时:
> 当前无法继续聊天。
---
# 第一百零六章 解除匹配流程
```text
用户选择解除匹配
↓
选择原因
↓
确认
↓
Match = unmatched
↓
Conversation关闭
↓
双方不再继续聊天
```
---
# 第一百零七章 解除匹配是否通知对方
建议:
> 系统通知对方“该匹配关系已结束”。
不要显示:
> 对方选择你的原因。
例如:
```text
当前匹配关系已结束,双方将无法继续发送消息。
```
---
# 第一百零八章 为什么不展示Unmatch原因
原因可能造成:
- 伤害
- 争执
- 报复
原因只用于:
> 内部产品分析。
---
# 第一百零九章 Match成功后的第一条系统消息
建议:
```text
你们互相喜欢,可以开始进一步了解了。
```
下面安全说明:
```text
请注意保护个人隐私,谨慎涉及转账、
借款、投资等资金往来。
```
---
# 第一百一十章 第一次聊天安全提醒
顶部NoticeBar显示一次。
用户关闭后:
> 当前Conversation不再重复顶部显示。
但风险命中仍可出现RiskNotice。
---
# 第一百一十一章 安全提醒本地状态
可存:
```text
conversationSafetyNoticeClosed[conversationId]
```
只是UI偏好。
不是安全业务真相。
---
# 第一百一十二章 账号封禁实时流程
后台封禁A:
```text
RiskService更新AccountStatus
↓
关闭A所有发送能力
↓
缓存失效
↓
WebSocket发送 account.status_changed
↓
客户端UserStore刷新
↓
聊天输入框全部禁用
```
---
# 第一百一十三章 封禁后已有消息
历史消息不删除。
对方看到:
> 当前用户暂时无法联系。
具体文案不要暴露内部风控细节。
---
# 第一百一十四章 临时限制与永久封禁区别
feature_limit:
> 可能只限制Like或消息。
temporary_suspend:
> 核心婚恋功能暂停。
ban:
> 严重限制账号。
MessageService每次发送都读取:
> 当前有效权限。
---
# 第一百一十五章 不只在登录时检查风控
用户登录后可能过几个小时才被限制。
因此:
> 每次发送消息必须重新检查账号聊天能力。
---
# 第一百一十六章 Redis可缓存聊天能力
可以缓存:
```text
chat_permission:{userId}
```
但User状态变化:
> 必须立即失效。
安全关键接口不能长期使用过期缓存。
---
# 第一百一十七章 消息接口限流
至少:
```text
按user
按conversation
按IP/Session
```
结合。
---
# 第一百一十八章 上传接口限流
防止:
> 用户疯狂上传图片占存储。
限制:
- 单用户单位时间上传数
- 单日总量
- 单文件大小
---
# 第一百一十九章 消息长度
文字建议:
```text
1~1000字符
```
具体可配置。
超过:
> 提示分段发送。
不需要支持一条几万字。
---
# 第一百二十章 空消息
纯空格:
> 拒绝。
Emoji:
> 正常允许。
---
# 第一百二十一章 URL链接
聊天中用户可能发送链接。
V1建议:
> 以纯文本展示。
不要自动:
> 生成富卡片预览。
原因:
- 安全
- 防钓鱼
- 开发简单
---
# 第一百二十二章 可疑链接提示
如果检测到:
> 外部网址
可以轻提示:
> 打开陌生链接请注意安全。
但不要每条网址都阻断。
---
# 第一百二十三章 V1不支持二维码扫描跳转
聊天图片里即使有二维码:
> 平台不主动识别并跳转。
减少诈骗跳转风险。
---
# 第一百二十四章 通知系统服务边界
所有业务模块:
不要自己写:
```text
INSERT notifications...
```
统一:
```text
NotificationService
```
---
# 第一百二十五章 Notification事件来源
例如:
```text
ProfileApproved
MutualMatchCreated
ActivityRegistrationApproved
MatchmakerRecommendationCreated
RiskActionCreated
```
由Notification模块消费。
---
# 第一百二十六章 通知失败补偿
建议建立:
```text
notification_delivery_tasks
```
或简单任务表/重试机制。
不强制MQ。
---
# 第一百二十七章 站内通知和微信通知分离
状态:
```text
in_app_created
wechat_pending
wechat_sent
wechat_failed
```
站内通知成功:
> 即认为核心通知存在。
微信订阅消息失败:
> 不影响业务。
---
# 第一百二十八章 通知发送优先级
高:
- 账号安全
- 活动取消
- 审核结果
- Match成功
中:
- 红娘推荐
- 活动报名结果
低:
- 普通运营提醒
---
# 第一百二十九章 不做营销推送
V1不推:
- “快来看看新用户”
- “今天桃花运爆棚”
- “已有3人偷偷喜欢你”
避免商业婚恋套路。
---
# 第一百三十章 喜欢我的通知
用户被Like:
V1可以:
> 系统通知有新的喜欢。
但不要过度刺激。
建议:
```text
有人表达了想进一步了解你的意愿。
```
也可以只在:
> 我的缘分 → 喜欢我的
展示。
具体通知频率可配置。
---
# 第一百三十一章 批量聚合通知
如果短时间收到多个Like:
不要发5条通知。
可以:
> 你收到了新的喜欢。
聚合处理。
---
# 第一百三十二章 聊天数据访问权限矩阵
| 角色 | 会话列表 | 聊天正文 |
|---|---:|---:|
| 用户本人 | 自己的 | 自己的 |
| 公益红娘 | 否 | 否 |
| 活动管理员 | 否 | 否 |
| 审核员 | 否 | 否 |
| 普通管理员 | 否 | 否 |
| 风控员 | 关联案件必要范围 | 特殊权限 |
| 超级管理员 | 默认否 | 特殊授权 |
---
# 第一百三十三章 聊天数据库查询接口
普通后台不要提供:
```text
GET /admin/users/{id}/messages
```
这种入口。
风控使用专门接口:
```text
GET /admin/risk/reports/{reportId}/conversation-context
```
只能围绕案件访问。
---
# 第一百三十四章 风控聊天查询范围
参数可以:
```text
beforeMessageId
afterMessageId
limit
```
限制上下文数量。
避免一次加载全部历史。
---
# 第一百三十五章 所有风控查询必须Audit
记录:
```text
operatorId
reportId
conversationId
range
reason
time
```
---
# 第一百三十六章 消息保留策略
V1不在本章拍死具体年限。
必须由:
> 数据生命周期政策 + 法律合规审查
确定。
系统需要支持:
- 按用户/时间删除或匿名化
- 注销处理
- 纠纷保留
- 安全调查保留
---
# 第一百三十七章 用户注销对聊天影响
注销后:
```text
can_send = false
```
历史Conversation中:
展示名可变为:
> 用户已注销
头像:
> 中性占位图。
---
# 第一百三十八章 注销用户消息内容
历史消息是否保留:
按平台数据保留政策处理。
不能简单因为注销:
> 让另一方历史聊天全部报错。
---
# 第一百三十九章 消息搜索
V1不做:
> 全局聊天内容搜索。
用户端也暂不需要聊天记录搜索。
降低开发与隐私复杂度。
---
# 第一百四十章 后台不做聊天大数据分析
V1不建设:
- 聊天情感分析
- AI全量监听
- 聊天画像
- 关系亲密度预测
风险检测只做:
> 最小必要的安全规则。
---
# 第一百四十一章 监控指标
技术监控:
```text
WebSocket在线连接数
连接成功率
重连率
消息发送成功率
消息发送P95
消息失败率
上传失败率
```
---
# 第一百四十二章 业务安全指标
```text
每千次会话举报数
被拉黑率
高频发送账号数
重复文本风险账号
资金类风险提醒数量
诈骗举报数
```
---
# 第一百四十三章 不把“聊天多”作为成功核心指标
聊天消息数量大:
> 不代表婚恋效果好。
真正关注:
```text
Match后聊天启动率
持续沟通率
正在了解率
成功牵手率
```
---
# 第一百四十四章 Conversation长期沉默
例如Match后:
> 30天双方都未发消息。
可以标记:
> inactive。
但V1不需要自动关闭。
---
# 第一百四十五章 是否做破冰提示
可以轻量提供:
```text
不知道怎么开始?
可以从兴趣、工作和周末生活聊起。
```
不需要AI。
---
# 第一百四十六章 破冰提示不要自动发送
只作为:
> 用户自己看的提示。
绝不能自动替用户发:
> “你好,你也喜欢旅行吗?”
---
# 第一百四十七章 聊天首屏示例
```text
← 王女士 ···
安全提醒
请保护个人隐私,谨慎涉及转账、
借款、投资等资金往来。 ×
你们互相喜欢
可以开始进一步了解了
[头像] 你好,很高兴认识你
你好,我也是
────────────────────────
😊 输入消息... +
```
---
# 第一百四十八章 Conversation关闭示例
```text
← 王女士
历史聊天内容……
────────────────────────
当前匹配关系已结束,
无法继续发送消息。
```
不显示Input。
---
# 第一百四十九章 被风控限制示例
```text
当前账号部分功能暂时受限,
暂时无法发送消息。
[查看账号状态]
```
---
# 第一百五十章 消息服务内部模块建议
```text
ConversationService
MessageService
MessagePermissionService
MessageRiskService
UnreadService
RealtimePushService
NotificationService
```
仍属于模块化单体。
---
# 第一百五十一章 MessagePermissionService
负责:
```text
用户是否属于Conversation
Match是否有效
Block关系
AccountStatus
Conversation状态
can_send
```
所有发送请求统一调用。
---
# 第一百五十二章 MessageRiskService
负责:
- 消息频率
- 重复文本
- 风险关键词
- 可疑外链
- 风险事件
不负责:
> 永久封禁决定。
严重事件交Risk模块。
---
# 第一百五十三章 UnreadService
统一维护:
```text
conversation unread
chat total
notification unread
total unread
```
防止多个模块各算一套。
---
# 第一百五十四章 RealtimePushService
只负责:
> 把已经发生的业务事件推给在线客户端。
不能把WebSocket当业务数据库。
---
# 第一百五十五章 Redis在实时消息中的用途
可以:
- userId → connection/node映射
- 在线状态
- 未读缓存
- Pub/Sub跨实例推送
如果V1只有单实例:
> Redis Pub/Sub甚至可以暂时不使用。
但接口设计应方便未来扩展。
---
# 第一百五十六章 多实例未来扩展
未来后端2台:
```text
Backend A
Backend B
```
用户A连接A。
用户B连接B。
消息保存后:
> Redis Pub/Sub通知B实例。
V1先预留。
---
# 第一百五十七章 不建议V1引入Kafka
实时聊天量在丹阳本地初期无需Kafka。
优先:
> PostgreSQL + Redis + WebSocket。
---
# 第一百五十八章 消息数据库写入优先
原则:
```text
先落库
↓
再推送
```
不要:
```text
先推给对方
↓
数据库写入失败
```
否则双方消息状态会错乱。
---
# 第一百五十九章 推送失败
消息已经落库:
> 仍是成功。
接收方下一次:
- 打开消息页
- WS重连
- 拉取增量
都能看到。
---
# 第一百六十章 消息同步Cursor
客户端保存:
```text
lastMessageSyncCursor
```
重连:
```text
GET /messages/sync?cursor=...
```
可作为未来接口。
---
# 第一百六十一章 V1是否必须做全局sync接口
不是绝对必须。
可以先:
> 重连后刷新Conversation列表 + 当前Conversation。
但建议预留:
```text
/messages/sync
```
以后更稳。
---
# 第一百六十二章 服务端事件顺序
事件至少包含:
```text
eventId
occurredAt
```
客户端遇到顺序异常:
最终以REST拉取的服务端状态为准。
---
# 第一百六十三章 网络恢复策略
断网时:
用户输入:
> 草稿保留。
发送失败:
> failed。
恢复网络:
不自动把所有失败消息无限发送。
建议:
> 用户点击重试
或仅对明确未提交成功的消息做有限重试。
---
# 第一百六十四章 图片消息弱网
图片上传过程中断:
> 显示失败。
重新上传。
不要产生:
> 空白Image消息。
---
# 第一百六十五章 安全降级
Risk关键词服务异常:
普通消息:
> 可以在满足基础安全条件下继续发送。
但:
- AccountStatus
- Block
- Conversation权限
这些核心安全检查不可绕过。
---
# 第一百六十六章 权限服务异常
如果无法判断:
> 当前用户是否属于Conversation。
必须:
> Fail Closed。
拒绝发送。
---
# 第一百六十七章 用户隐私设置和聊天
用户关闭:
> visibleInSearch
不会自动关闭已有Match聊天。
隐私曝光和已有关系:
> 分开。
---
# 第一百六十八章 paused状态和聊天
用户暂停寻找:
> 仍可继续已有聊天。
暂停的含义是:
> 不寻找新人。
不是:
> 强制断掉已有沟通。
---
# 第一百六十九章 getting_to_know和聊天
正常保留。
甚至这是聊天最主要阶段。
---
# 第一百七十章 successful状态和聊天
成功牵手后:
> 已有双方Conversation继续保留。
平台不强制关闭。
---
# 第一百七十一章 多Match聊天
用户可能同时有多个Mutual Match。
每个Conversation独立。
V1不人为限制:
> 只能聊一个人。
---
# 第一百七十二章 红娘是否知道用户有多少会话
红娘可以看到:
> 用户匹配/服务摘要
但不需要看到:
- 聊天对象详情列表
- 聊天内容
只提供服务必要的有限状态。
---
# 第一百七十三章 防骚扰优先级
```text
Block
>
Account Restriction
>
Conversation Status
>
Message Rate Limit
>
Risk Warning
```
---
# 第一百七十四章 用户主动权
任何时候用户都能:
- 不回复
- 解除匹配
- 拉黑
- 举报
不需要经过红娘批准。
---
# 第一百七十五章 Chat API验收
必须测试:
```text
无Match发消息
单向Like发消息
有效Match发消息
已Unmatch发消息
被Block发消息
账号被封禁发消息
重复clientMessageId
消息超长
空消息
图片失败
```
---
# 第一百七十六章 实时通信验收
必须测试:
- 双方在线
- 一方离线
- WS断线重连
- 微信切后台再回来
- Token过期
- 账号实时封禁
- 消息重复推送
- 消息乱序
- 推送失败后REST恢复
---
# 第一百七十七章 未读验收
确保:
```text
聊天列表未读
消息Tab Badge
Conversation已读
系统通知未读
```
数据一致。
---
# 第一百七十八章 反骚扰验收
模拟:
- 1秒发100条
- 多会话复制广告
- 连续发送联系方式
- 多人举报
- 资金关键词
- 多次拉黑
- 正常用户快速聊天
必须:
> 拦异常,但不能严重误伤正常沟通。
---
# 第一百七十九章 隐私验收
必须测试:
- 红娘查看聊天 → 拒绝
- 活动管理员查看聊天 → 拒绝
- 普通管理员获取聊天 → 拒绝
- 风控员无案件访问 → 拒绝
- 有权限风控员关联举报访问 → 允许并审计
---
# 第一百八十章 V1明确不开发
```text
语音通话
视频通话
语音房
群聊
直播
红包
支付
礼物
阅后即焚
消息撤回
聊天记录全局搜索
AI自动回复
AI代聊
自动情感分析
恋爱亲密度评分
“正在输入”状态
已读回执展示
```
---
# 第一百八十一章 开发优先级
## P0
```text
Conversation
Text Message
Message Permission
REST发送
WebSocket接收
未读
历史分页
失败重试
Unmatch关闭
Block关闭
AccountStatus实时限制
```
---
## P1
```text
Image Message
RiskNotice
发送限频
重复文本检测
系统通知
微信订阅消息封装
```
---
## P2
```text
更完善的增量Sync
聚合通知
反Spam规则优化
消息性能统计
```
---
# 第一百八十二章 最终架构
```text
┌─────────────────┐
│ 微信小程序客户端 │
└───────┬─────────┘
│
HTTPS │ WSS
↓ │ ↓
┌──────────┐ │ ┌──────────────┐
│ REST API │ │ │ WebSocket │
└────┬─────┘ │ │ Gateway │
│ │ └──────┬───────┘
↓ │ │
MessageService │ │
│ │ │
┌─────┼─────┐ │ │
↓ ↓ ↓ │ │
Permission Risk Unread│ │
│ │ │ │ │
└─────┼─────┘ │ │
↓ │ │
PostgreSQL │ Redis
│ │
↓ │
RealtimePush ─────┘
```
---
# 第一百八十三章 最终设计原则
V1.0实时聊天与消息体系必须坚持:
> **没有双向喜欢,就没有聊天。**
> **消息先落库,再实时推送。**
> **每条消息都有客户端幂等ID。**
> **WebSocket断线不能造成消息丢失。**
> **拉黑、解除匹配和封禁必须立即停止发送。**
> **暂停寻找不影响已有正常聊天。**
> **工作人员默认没有查看私人聊天的权限。**
> **风险关键词用于提醒和发现风险,不用于简单粗暴定罪。**
> **用户可以自主拉黑、举报、结束匹配。**
> **V1只做可靠沟通,不把聊天模块做成复杂社交平台。**
最终要达到的体验不是:
> “功能很多。”
而是:
> **双方愿意聊的时候,消息稳定、简单、安全;不愿意继续的时候,可以立即、明确、没有负担地结束沟通。**