# 丹阳公益婚恋服务平台 # 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只做可靠沟通,不把聊天模块做成复杂社交平台。** 最终要达到的体验不是: > “功能很多。” 而是: > **双方愿意聊的时候,消息稳定、简单、安全;不愿意继续的时候,可以立即、明确、没有负担地结束沟通。**