# 丹阳公益婚恋服务平台 # V1.0 核心业务规则、状态机与异常处理设计 版本:V1.0 适用范围:微信小程序用户端、公益红娘工作台、运营管理后台 目标:保证关键业务状态一致、规则明确、异常可恢复、并发不重复、前后台行为统一 --- # 第一章 文档目标 本文件重点解决以下问题: - 用户什么时候可以进入匹配 - 审核状态怎么流转 - 喜欢和双向喜欢如何生成 - 什么情况下可以聊天 - 拉黑、解除匹配后发生什么 - “正在了解”和“成功牵手”如何处理 - 活动报名、审核、签到如何流转 - 红娘服务如何分配和结束 - 举报、风控、封禁如何处理 - 并发操作时如何避免重复 - 异常发生后如何恢复 - 前端、后端、后台如何保持同一状态 核心原则: > **所有关键业务都必须有明确状态机,不能通过页面临时逻辑决定业务结果。** --- # 第二章 状态机设计总原则 所有核心状态都遵循: ```text 当前状态 ↓ 校验操作权限 ↓ 校验业务前置条件 ↓ 执行状态迁移 ↓ 写数据库 ↓ 触发副作用 ↓ 通知前端/用户 ``` 禁止: ```text 页面点按钮 ↓ 前端直接改状态 ↓ 后端被动接受 ``` --- # 第三章 状态迁移必须服务端控制 例如: 用户不能直接提交: ```json { "relationshipStatus": "matched_successfully" } ``` 服务端必须验证: - 当前是否存在有效Match - 是否有成功牵手请求 - 对方是否确认 - 双方账号是否正常 满足后才允许状态改变。 --- # 第四章 用户总状态体系 用户平台状态由四个维度共同决定: ```text 账号状态 AccountStatus 实名状态 VerificationStatus 资料审核状态 ReviewStatus 婚恋状态 RelationshipStatus ``` 四者彼此独立,但共同决定用户能力。 --- # 第五章 AccountStatus 状态: ```text normal reviewing_risk limited suspended banned closed ``` --- # 第六章 AccountStatus能力矩阵 | 状态 | 登录 | 查看自己 | 推荐 | 喜欢 | 聊天 | 活动 | 红娘 | |---|---:|---:|---:|---:|---:|---:|---:| | normal | 是 | 是 | 是 | 是 | 是 | 是 | 是 | | reviewing_risk | 是 | 是 | 否/受限 | 否 | 受限 | 受限 | 受限 | | limited | 是 | 是 | 受限 | 否 | 受限 | 视策略 | 视策略 | | suspended | 是 | 是 | 否 | 否 | 否 | 否 | 否 | | banned | 是 | 是 | 否 | 否 | 否 | 否 | 否 | | closed | 否/仅注销提示 | 否 | 否 | 否 | 否 | 否 | 否 | 实际限制由RiskAction进一步决定。 --- # 第七章 VerificationStatus ```text not_verified verifying verified failed manual_review ``` 只有: ```text verified ``` 才能进入资料完整填写和正式匹配流程。 --- # 第八章 Profile Review状态 ```text not_submitted pending processing approved need_edit rejected ``` --- # 第九章 审核状态机 ```text not_submitted ↓ 提交 pending ↓ 领取 processing ├──────────────┐ ↓ ↓ approved need_edit ↓ 用户修改重提 pending processing ↓ 严重违规 rejected ``` --- # 第十章 审核允许迁移 允许: ```text not_submitted → pending pending → processing processing → approved processing → need_edit processing → rejected need_edit → pending ``` --- # 第十一章 审核禁止迁移 禁止: ```text approved → pending ``` 直接由普通前端操作触发。 如果用户修改敏感资料: 应创建: > 新的ReviewTask 而不是把旧审核记录改回pending。 --- # 第十二章 敏感资料修改规则 以下修改必须重新审核: - 主头像 - 生活照片 - 自我介绍 - 婚姻状态 - 其他人工审核字段 新流程: ```text 原资料 approved ↓ 用户修改 ↓ 创建 profile_change review ↓ 新内容待审核 ``` --- # 第十三章 修改期间展示规则 建议V1采用: > 已审核旧版本继续对外展示,新版本审核通过后替换。 这样避免用户修改一句自我介绍后: > 整个账号退出匹配池。 但以下情况例外: ### 婚姻状态变更 如果从: > 未婚 → 离异等重大变化 建议立即暂停推荐,待重新审核。 --- # 第十四章 审核领取并发规则 两个审核员同时点击领取。 仅第一个成功。 数据库: ```text UPDATE review_tasks SET status='processing' WHERE id=? AND status='pending' ``` 影响行数: ```text 1 = 成功 0 = 已被别人领取 ``` 前端提示: > 该任务已由其他工作人员领取。 --- # 第十五章 审核超时规则 如果审核员领取后长时间未处理,例如: > 30分钟或运营配置时间 可以: - 提醒审核员 - 管理员重新分配 不要自动直接把任务变回pending导致重复操作。 --- # 第十六章 RelationshipStatus ```text searching getting_to_know paused matched_successfully service_exited ``` --- # 第十七章 婚恋状态迁移 ```text searching ├→ paused ├→ getting_to_know └→ service_exited paused ├→ searching └→ service_exited getting_to_know ├→ searching ├→ paused ├→ matched_successfully └→ service_exited matched_successfully └→ 特殊人工恢复/关系结束流程 service_exited └→ 用户重新启用婚恋服务(后续规则) ``` --- # 第十八章 searching规则 用户在searching状态: 允许: - 出现在推荐池 - 主动找对象 - 喜欢别人 - 被别人喜欢 - 接受红娘推荐 - 参加活动 前提: > 账号和审核状态正常。 --- # 第十九章 paused规则 paused时: ```text recommendation_enabled = false visible_in_recommendations = false ``` 默认: > 不进入推荐池。 已有聊天: > 保留。 已有Match: > 保留。 --- # 第二十章 getting_to_know规则 用户设置: > 正在了解 时必须明确是否: ```text pauseOtherRecommendations = true/false ``` 如果true: - 不再生成新推荐 - 不再出现在找对象列表 - 已有匹配关系保留 如果false: > 仍允许继续使用匹配功能。 --- # 第二十一章 matched_successfully规则 双方确认成功牵手后: ```text relationship_status = matched_successfully recommendation_enabled = false visible_in_recommendations = false ``` 双方: - 不再收到新推荐 - 不再出现在找对象 - 不再接受普通红娘推荐 - 已有聊天保留 --- # 第二十二章 成功牵手不可单方完成 流程: ```text A发起成功牵手 ↓ status = pending ↓ B收到确认 ├→ 确认 │ ↓ │ successful │ └→ 拒绝 ↓ declined ``` 只有确认后: > 双方婚恋状态一起更新。 --- # 第二十三章 成功牵手并发规则 A和B可能同时发起。 系统必须识别: > 同一个Match已有pending成功请求。 第二个请求: 可以直接合并成确认。 不要生成两条独立成功请求。 --- # 第二十四章 成功牵手取消问题 V1不建议用户随意一键取消“成功牵手”。 如果关系结束并重新寻找: 建议走: > 重新开启婚恋服务 并记录历史。 不能删除之前成功记录。 --- # 第二十五章 用户关系基础状态 单向关系: ```text neutral liked passed blocked ``` 双向关系: ```text mutual_match ``` --- # 第二十六章 Like状态机 初始: ```text neutral ``` A喜欢B: ```text neutral → liked ``` 如果B已经喜欢A: ```text liked + reverse liked ↓ mutual_match ``` --- # 第二十七章 Like前置条件 必须同时满足: - A账号正常 - B账号正常 - A资料审核通过 - B资料审核通过 - A当前允许寻找 - B当前允许被发现 - A没有拉黑B - B没有拉黑A - A != B --- # 第二十八章 Like禁止场景 禁止: - 喜欢自己 - 喜欢已封禁用户 - 喜欢被自己拉黑用户 - 喜欢已经拉黑自己的用户 - 审核未通过用户点击喜欢 - 已退出婚恋服务用户点击喜欢 --- # 第二十九章 重复喜欢 A已经liked B。 再次请求: > 不创建新数据。 返回: ```text ALREADY_LIKED ``` 或者幂等返回: ```text relationStatus = liked ``` 推荐采用: > 幂等成功。 前端体验更稳定。 --- # 第三十章 取消喜欢 仅适用于: > 尚未形成mutual_match。 如果已经双向匹配: 不能: > 取消喜欢来解除关系。 必须: > 解除匹配。 --- # 第三十一章 Pass规则 A点击不合适: ```text neutral / liked未匹配 → passed ``` 如果A之前liked但尚未匹配: 可以: > 覆盖为passed 并清除/失效liked。 实现上建议保留历史事件,但当前关系以passed为准。 --- # 第三十二章 Pass冷却 用户pass后: 系统在配置周期内不再推荐。 例如: > 180天。 后续可以允许重新出现。 但blocked: > 永久排除,直到解除拉黑。 --- # 第三十三章 Mutual Match状态机 当双方liked: ```text no_match ↓ active ``` 之后: ```text active ├→ getting_to_know ├→ unmatched └→ successful ``` --- # 第三十四章 Mutual Match唯一规则 一对用户只能存在: > 一个当前Match实体。 标准化: ```text userA = min(user1,user2) userB = max(user1,user2) ``` 数据库唯一约束。 --- # 第三十五章 同时点赞并发 A和B同一毫秒点击喜欢。 两边事务都可能检测。 最终依赖: - user_relation唯一约束 - match pair唯一约束 - duplicate key捕获 保证: > 只创建一个Match。 --- # 第三十六章 Match创建后副作用 Match成功后: 主事务必须完成: - Match记录 - Conversation记录 - ConversationMembers 事务提交后: - 创建系统通知 - WebSocket通知 - 统计+1 通知失败: > 不能回滚Match。 --- # 第三十七章 Chat开启规则 只有: ```text match.status = active OR getting_to_know ``` 且: - 双方账号可用 - 双方未拉黑 - conversation.can_send = true 才能聊天。 --- # 第三十八章 没有双向喜欢不能聊天 无论用户是否: - 搜索到对方 - 被红娘推荐 - 活动认识 - 单向喜欢 都不能直接聊天。 必须形成: > 双方明确同意。 --- # 第三十九章 红娘推荐与聊天关系 红娘推荐: ```text 红娘 → 用户A推荐B ``` 不创建: - like - match - conversation A点击喜欢后: 仍然等B喜欢A。 --- # 第四十章 活动互选与聊天 活动结束: A选择B感兴趣。 B也选择A。 系统可以直接视为: > 双方明确意向 因此可以生成Match。 但前端应明确告知: > 你们在本次活动中互相选择,可以开始交流。 --- # 第四十一章 Conversation状态 建议: ```text active closed ``` 不需要V1搞复杂。 --- # 第四十二章 Conversation关闭场景 以下事件关闭发送能力: - 解除匹配 - 任一方拉黑 - 任一方账号封禁 - 账号关闭 历史聊天可以保留。 --- # 第四十三章 Unmatch规则 任何一方可以解除匹配。 请求: ```text match.status = active/getting_to_know ``` 执行: ```text match.status → unmatched conversation.can_send → false ``` --- # 第四十四章 解除匹配后的推荐 默认: 双方进入较长排除期。 建议: > 不再主动推荐。 是否未来重新出现,可配置。 V1建议: > 默认长期排除。 --- # 第四十五章 解除匹配不等于拉黑 解除匹配: > 不继续了解。 拉黑: > 不希望对方再看到/联系自己。 两者必须分开。 --- # 第四十六章 Block状态机 ```text neutral / liked / mutual_match / unmatched ↓ blocked ``` 拉黑优先级最高。 --- # 第四十七章 拉黑后的即时副作用 必须立即: - 停止双方聊天 - 移除推荐 - 移除搜索可见关系 - 移除喜欢列表展示 - 红娘候选排除 - 活动推荐关系排除 --- # 第四十八章 解除拉黑 解除后: ```text blocked → neutral ``` 但: - 不恢复旧Like - 不恢复旧Match - 不恢复旧Conversation发送能力 如果以后重新匹配: > 重新走喜欢流程。 --- # 第四十九章 举报与拉黑关系 举报不自动拉黑。 用户可以: > 举报后选择是否同时拉黑。 严重风险场景前端可以提示: > 是否同时拉黑该用户? --- # 第五十章 Message状态机 客户端消息: ```text local ↓ sending ├→ sent └→ failed ``` 服务端消息: ```text accepted ↓ persisted ↓ delivered(可选) ↓ read ``` V1数据库可只保留: > sent/read相关必要状态。 --- # 第五十一章 消息幂等规则 每条发送请求: ```text sender_id + client_message_id ``` 唯一。 弱网重发: 返回原消息。 不能生成重复文本。 --- # 第五十二章 消息发送前置校验 发送前必须校验: 1. Conversation存在 2. 当前用户属于Conversation 3. Conversation可发送 4. Match有效 5. 双方未拉黑 6. 双方账号正常 7. 内容合法 8. 频率未超限 --- # 第五十三章 Message发送异常恢复 情况: > 数据库已经保存,但WebSocket返回失败。 客户端重试同一clientMessageId: 服务端查询原消息并返回。 这样避免: > 用户看到重复消息。 --- # 第五十四章 未读数规则 接收方新消息: ```text unread_count + 1 ``` 进入会话并读到: ```text last_read_message_id ``` 服务端计算/更新: > unread_count。 --- # 第五十五章 已读并发 客户端可能重复调用read。 接口必须幂等。 只允许: > lastReadMessage位置向前推进。 不能因为旧请求晚到: > 把已读位置回退。 --- # 第五十六章 聊天风险提示规则 检测到普通风险关键词: > 提醒,不拦截。 例如: - 转账 - 借钱 - 投资 系统插入: > risk_notice。 --- # 第五十七章 严重消息风险 如果命中明显诈骗模板、高频群发等: 可以: - 创建RiskEvent - 提高风险分 - 临时限速 - 进入人工关注 但V1不建议: > 单凭一个关键词直接永久封禁。 --- # 第五十八章 Activity状态机 ```text draft ↓ 发布 registration_open ↓ 截止 registration_closed ↓ 开始 ongoing ↓ 结束 ended ``` 另有: ```text draft / registration_open ↓ cancelled ``` --- # 第五十九章 活动状态迁移规则 允许: ```text draft → registration_open registration_open → registration_closed registration_closed → ongoing ongoing → ended ``` 管理员取消: ```text draft → cancelled registration_open → cancelled registration_closed → cancelled ``` --- # 第六十章 活动禁止迁移 禁止普通操作: ```text ended → registration_open cancelled → ongoing ``` 如果运营误操作: > 应复制创建新活动,而不是倒退旧活动。 --- # 第六十一章 ActivityRegistration状态机 ```text not_applied ↓ pending ├→ approved ├→ rejected └→ cancelled ``` 若活动无需审核: ```text not_applied → approved ``` --- # 第六十二章 报名前置条件 必须: - 用户实名 - 用户审核通过 - 账号正常 - 活动报名中 - 年龄符合 - 未重复报名 - 名额可用 --- # 第六十三章 活动年龄规则 年龄必须: > 服务端根据birth_date计算。 不能相信前端传age。 --- # 第六十四章 活动报名并发 如果最后一个名额: 多人同时报名。 必须在事务中: - 锁定活动或计数资源 - 检查剩余名额 - 写报名 最终: > 不能超额。 --- # 第六十五章 待审核是否占名额 V1必须明确规则。 建议: > pending暂不占正式名额,approved才占名额。 原因: 工作人员需要审核。 但这样可能: > 待审核人数大于剩余名额。 后台应提示: > 通过时按剩余名额校验。 --- # 第六十六章 无需审核活动 如果: ```text need_review = false ``` 报名事务中直接: > approved并占名额。 --- # 第六十七章 报名拒绝 拒绝后: ```text pending → rejected ``` 必须记录原因。 用户收到通知。 --- # 第六十八章 活动取消 活动取消后: - 所有用户收到通知 - 报名记录保留 - 签到关闭 - 不物理删除报名 状态: ```text activity = cancelled ``` --- # 第六十九章 签到前置条件 只有: - activity有效 - registration = approved - 未签到 - token有效 才可签到。 --- # 第七十章 重复签到 重复扫码: 返回: > 已签到 + 原签到时间。 不要报系统错误。 --- # 第七十一章 签到Token规则 签到二维码Token: - 短时有效 - 签名 - 不直接暴露userId - 与activity绑定 过期: > 客户端重新获取。 --- # 第七十二章 活动反馈规则 只有: - 已报名 - 活动已结束 才允许提交反馈。 是否必须签到: 建议: > 只有已签到用户可提交完整活动反馈。 未签到用户可提交: > 未参与原因(以后可加)。 --- # 第七十三章 活动互选规则 用户只能选择: - 同一活动 - 实际允许被选择的参与者 - 未被拉黑 - 账号正常 不能通过修改userId选择任意平台用户。 --- # 第七十四章 MatchmakerService状态机 ```text submitted ↓ 分配 assigned ↓ 开始服务 in_service ├→ waiting_user │ ↓ │ in_service └→ completed submitted/assigned → cancelled ``` --- # 第七十五章 红娘服务申请规则 用户可以申请: - 推荐对象 - 调整择偶条件 - 联系意向对象 - 活动帮助 - 匹配困难 - 沟通帮助 同类型服务若已有: > in_service 建议限制重复提交。 返回: > SERVICE_ALREADY_ACTIVE --- # 第七十六章 红娘接单并发 两位红娘同时接单。 采用数据库原子更新。 只允许一个成功。 失败: > 该服务已由其他红娘接单。 --- # 第七十七章 红娘服务权限 红娘只能操作: - 自己被分配的服务 - 或所在机构授权服务 不能通过修改serviceId查看其他机构数据。 --- # 第七十八章 红娘推荐前置条件 推荐B给A前必须: - A服务有效 - B审核通过 - B账号正常 - B可被推荐 - 双方无拉黑 - 双方required条件不冲突 --- # 第七十九章 红娘不能突破硬条件 即便红娘认为“很合适”。 如果用户设置: > 必须符合 而候选人不符合: 系统不允许推荐。 除非: > 用户本人先修改条件。 --- # 第八十章 红娘服务完成 完成前建议至少: - 有跟进记录 - 或有明确处理结果 例如: ```text 已推荐3位 用户暂时暂停服务 用户已成功牵手 未找到合适对象 ``` --- # 第八十一章 红娘超时提醒 如果服务: > 3天/配置时间未跟进 后台显示: > 超时待跟进。 不自动结束服务。 --- # 第八十二章 Report状态机 ```text pending ↓ 受理 processing ├→ confirmed ├→ rejected └→ insufficient_evidence ``` --- # 第八十三章 举报结果与处置分离 Report结果: > 举报是否成立。 RiskAction: > 对用户采取什么措施。 不要把二者混成一个status。 例如: ```text report = confirmed riskAction = warning ``` 或: ```text report = confirmed riskAction = ban ``` --- # 第八十四章 RiskLevel状态 ```text normal watch high critical ``` 风险等级用于: > 排序和关注。 不是直接等于账号状态。 --- # 第八十五章 风险处置状态 RiskAction: ```text warning feature_limit temporary_suspend ban manual_investigation ``` --- # 第八十六章 风控副作用 例如 temporary_suspend: 必须同步: - AccountStatus - Match推荐排除 - Like禁止 - Chat发送禁止 - 活动报名禁止 - 红娘服务限制 --- # 第八十七章 风控处置事务 建议主事务: ```text 创建RiskAction ↓ 更新User AccountStatus ↓ 写AuditLog ``` 事务后: - WebSocket通知客户端 - Notification通知用户 - 缓存失效 --- # 第八十八章 风控状态实时生效 不能等用户下次登录。 如果用户正在聊天时被封禁: 下一次: - WebSocket状态事件 - 或任何API响应 必须让客户端更新状态并停止发送。 --- # 第八十九章 Appeal申诉状态机 ```text pending ↓ processing ├→ approved └→ rejected ``` approved: 可能: - 撤销RiskAction - 恢复AccountStatus 但必须保留原始风险记录。 --- # 第九十章 风控误判恢复 撤销封禁: ```text risk_action.revoked_at = now ``` 更新用户: > 根据仍然生效的其他RiskAction重新计算最终AccountStatus。 不能简单: ```text account_status = normal ``` 因为可能还有其他限制。 --- # 第九十一章 Notification规则 业务状态变化后产生通知。 典型事件: - 审核通过 - 审核退回 - 双向喜欢 - 红娘推荐 - 活动审核通过 - 活动取消 - 风险处置 - 成功牵手确认 --- # 第九十二章 通知失败不影响主业务 例如: > 活动报名已审核通过 Notification服务失败。 不能: > 把报名状态回滚。 应: - 业务成功 - 通知进入补偿队列/任务 --- # 第九十三章 通知去重 相同业务事件: 例如同一match: > 不得重复发送10次“互相喜欢”。 建议: ```text event_type + business_id + user_id ``` 做去重Key。 --- # 第九十四章 用户删除/注销状态机 V1建议: ```text normal account ↓ 用户申请注销 closing(可选) ↓ 完成 closed ``` 如果不做等待期: 可以直接: > closed 但仍需服务端完成数据退出流程。 --- # 第九十五章 注销后的副作用 必须: - 停止推荐 - 隐藏资料 - 禁止Like - 禁止新消息 - 停止红娘服务 - 取消未开始活动报名视业务处理 - 关闭登录会话 --- # 第九十六章 注销不删除历史关系 保留: - Match历史 - 举报 - 审核 - 审计 - 活动记录 展示时: > 已注销用户 而不是查询失败导致数据链断裂。 --- # 第九十七章 Session状态异常 Token过期: ```text AUTH_EXPIRED ``` 前端: - 保存安全草稿 - 尝试refresh - refresh失败才回登录 --- # 第九十八章 服务端状态比前端新 例如前端显示: > 审核通过 但后台刚封禁。 任何关键API: > 必须重新校验数据库/缓存中的最新账号状态。 不能因为前端旧状态继续执行。 --- # 第九十九章 缓存一致性规则 关键状态变化: 必须主动失效相关缓存。 例如拉黑: ```text 推荐缓存 用户详情缓存 关系缓存 红娘候选缓存 ``` 都需要失效。 --- # 第一百章 推荐缓存不能绕过状态校验 即使推荐列表已经缓存: 返回给客户端之前仍需快速检查: - target账号 - target审核状态 - 是否拉黑 - 是否暂停曝光 --- # 第一百零一章 用户详情失效 用户打开详情时: 如果对方刚被封禁。 返回: ```text TARGET_UNAVAILABLE ``` 前端: > 该用户当前不可查看。 --- # 第一百零二章 关键业务错误分类 分为: ```text 可重试错误 不可重试业务错误 权限错误 状态冲突 系统错误 ``` --- # 第一百零三章 可重试错误 例如: - 网络超时 - 短暂数据库连接失败 - 对象存储临时失败 前端: > 可以重试。 --- # 第一百零四章 不可重试业务错误 例如: ```text PROFILE_NOT_APPROVED ACTIVITY_FULL BLOCKED_RELATION TARGET_UNAVAILABLE ``` 前端不能无限重试。 应改变页面状态。 --- # 第一百零五章 状态冲突 例如: 审核员操作: > 任务已被别人处理。 返回: ```text STATE_CONFLICT ``` 前端: > 刷新当前数据。 --- # 第一百零六章 系统错误 后端500: 前端统一: > 操作暂时未完成,请稍后重试。 不能展示: - SQL异常 - Java堆栈 - Node错误对象 --- # 第一百零七章 幂等业务总览 必须幂等: ```text Like Pass Block 提交审核 活动报名 活动签到 红娘申请 消息发送 举报 成功牵手请求 ``` --- # 第一百零八章 幂等成功优先 如果同一请求重复到达,但第一次已经成功: 推荐返回: > 原成功结果 而不是: > “重复错误”。 这样弱网体验更好。 --- # 第一百零九章 数据库唯一约束兜底 关键唯一约束: - user relation - match pair - activity registration - message client ID - conversation match ID 应用逻辑不能代替数据库约束。 --- # 第一百一十章 事务与副作用边界 原则: > 核心业务数据在事务内。 > 通知、统计、推送等副作用在事务后。 --- # 第一百一十一章 双向喜欢事务 事务内: ```text 写liked 检查reverse liked 创建match 创建conversation 创建members ``` 事务后: ```text 通知 WebSocket 统计 ``` --- # 第一百一十二章 活动报名事务 事务内: ```text 检查活动 检查名额 创建/更新registration ``` 事务后: ```text 发送报名通知 统计 ``` --- # 第一百一十三章 举报处理事务 事务内: ```text 更新report 创建risk event 创建risk action 更新account status audit ``` 事务后: ```text 通知 WebSocket 缓存失效 ``` --- # 第一百一十四章 超时补偿任务 建议至少有: - 通知补发 - 活动状态补正 - 审核超时提醒 - 红娘跟进超时提醒 - 风险状态重算 - 缓存重建 --- # 第一百一十五章 失败补偿原则 如果副作用失败: > 可重试。 如果核心事务失败: > 整体回滚。 不要出现: > Match没创建,但发了“互相喜欢”通知。 --- # 第一百一十六章 软删除业务规则 用户照片删除: > soft delete。 活动删除: > 如果草稿可soft delete。 已发布活动: > 优先cancelled。 不能物理删除造成历史断裂。 --- # 第一百一十七章 状态操作审计范围 后台以下动作必须Audit: - 审核通过/退回 - 用户封禁/解封 - 风控处置 - 红娘分配 - 活动取消 - 权限调整 - 查看敏感数据 - 匹配规则修改 --- # 第一百一十八章 普通用户操作日志 不需要所有点击都做Audit。 但关键业务事件应留业务记录: - Like - Match - Unmatch - Block - 举报 - 成功牵手 --- # 第一百一十九章 异常场景一:喜欢时对方被封禁 流程: ```text A打开旧详情 ↓ B刚被封禁 ↓ A点击喜欢 ↓ 服务端重新校验 ↓ TARGET_UNAVAILABLE ``` 前端: > 该用户当前不可继续了解。 并移除卡片。 --- # 第一百二十章 异常场景二:双方同时解除/拉黑 A解除匹配,B同时拉黑A。 最终: - Match = unmatched - Block关系存在 - Conversation关闭 Block优先级高。 --- # 第一百二十一章 异常场景三:活动最后一个名额 A和B同时审核通过。 数据库事务保证: > 只有一个通过。 另一个: ```text ACTIVITY_FULL ``` 工作人员界面刷新。 --- # 第一百二十二章 异常场景四:报名时活动被取消 客户端打开旧页面。 提交报名。 服务端: > 检查activity.status 返回: ```text ACTIVITY_NOT_OPEN ``` 前端刷新活动详情。 --- # 第一百二十三章 异常场景五:聊天中对方拉黑 A正在输入。 B拉黑A。 A发送: ```text BLOCKED_RELATION ``` 前端: - 停止发送 - 关闭输入框 - 显示“当前无法继续聊天” --- # 第一百二十四章 异常场景六:审核中用户修改资料 V1建议: 审核pending/processing期间: > 禁止修改正在审核的关键字段。 提示: > 资料正在审核中,审核完成后可继续修改。 避免审核版本混乱。 --- # 第一百二十五章 异常场景七:红娘候选失效 红娘打开候选B。 B随后暂停寻找。 红娘点击推荐: 服务端重新校验。 返回: ```text TARGET_UNAVAILABLE ``` 候选从列表移除。 --- # 第一百二十六章 异常场景八:成功牵手确认时Match已解除 A发起成功。 期间双方解除匹配。 B再点击确认。 服务端: ```text MATCH_NOT_ACTIVE ``` 成功请求标记: > cancelled/invalid。 --- # 第一百二十七章 异常场景九:用户注销时有未开始活动 V1建议: 注销前提示: > 你有已报名活动,注销后报名将自动取消。 用户确认注销后: - 未开始活动报名 → cancelled - 已结束活动记录保留 --- # 第一百二十八章 异常场景十:管理员误重复处理举报 第二次resolve: 如果Report已经final状态: 返回: ```text REPORT_ALREADY_RESOLVED ``` 不能创建第二个重复RiskAction。 --- # 第一百二十九章 业务优先级冲突规则 当多个状态冲突时: 优先级建议: ```text 账号安全状态 > 拉黑关系 > 审核状态 > 婚恋状态 > 普通Match关系 > UI偏好 ``` --- # 第一百三十章 示例:用户审核通过但被封禁 即使: ```text review = approved ``` 但: ```text account = banned ``` 最终: > 禁止匹配和聊天。 AccountStatus优先。 --- # 第一百三十一章 示例:双方Match但一方拉黑 即使: ```text match = active ``` 但: ```text block = true ``` 最终: > 不能聊天。 Block优先。 --- # 第一百三十二章 示例:正在了解但用户主动暂停 如果: ```text relationship = getting_to_know ``` 并且: ```text recommendation_enabled = false ``` 最终: > 不推荐新人,但保留已有聊天。 --- # 第一百三十三章 状态最终来源 最终业务真相来自: > PostgreSQL。 Redis: > 缓存。 前端Store: > 展示。 任何冲突: > 以服务端数据库状态为准。 --- # 第一百三十四章 状态更新时间 所有状态变化必须包含: ```text updated_at ``` 关键状态应额外记录: ```text approved_at matched_at unmatched_at successful_at processed_at ``` 方便审计和统计。 --- # 第一百三十五章 状态变更原因 以下状态必须记录原因: - 审核need_edit/rejected - 解除匹配 - 举报处理 - 风控处置 - 活动拒绝 - 账号封禁 - 申诉处理 不能只有状态没有原因。 --- # 第一百三十六章 用户可见原因与后台原因分离 例如封禁: 后台内部: > 多次举报+疑似诈骗话术。 用户前台: > 账号因安全风险暂时受限。 必要时再显示合规的具体说明。 避免泄露举报人信息。 --- # 第一百三十七章 状态机测试策略 每一个状态机至少测试: - 正常前向迁移 - 非法逆向迁移 - 重复请求 - 并发请求 - 权限不足 - 对象失效 - 网络重试 --- # 第一百三十八章 审核状态测试 必须覆盖: ```text not_submitted → pending pending → processing processing → approved processing → need_edit need_edit → pending ``` 同时测试: ```text approved → pending ``` 被拒绝。 --- # 第一百三十九章 Match测试 必须覆盖: - 单向Like - 双向Like - 同时Like - 重复Like - 拉黑后Like - Unmatch后聊天 - 成功牵手确认 --- # 第一百四十章 活动测试 必须覆盖: - 正常报名 - 重复报名 - 最后名额并发 - 审核通过 - 活动取消 - 重复签到 - Token过期 --- # 第一百四十一章 红娘测试 必须覆盖: - 重复申请 - 两人同时接单 - 推荐失效用户 - 红娘越权查看 - 已完成服务再次操作 --- # 第一百四十二章 风控测试 必须覆盖: - 举报成立 - 举报不成立 - 多次举报 - 封禁实时生效 - 解封 - 申诉通过 - 多个RiskAction同时存在 --- # 第一百四十三章 前后端状态码统一 前端不要自己推断: > “按钮灰了所以应该是审核中”。 后端明确返回: ```text reviewStatus accountStatus relationshipStatus relationStatus activityStatus serviceStatus ``` --- # 第一百四十四章 状态字典统一 所有枚举建议放共享文档/代码包。 例如: ```text AccountStatus ReviewStatus RelationshipStatus MatchStatus RegistrationStatus MatchmakerServiceStatus ReportStatus RiskLevel ``` 避免前后端分别定义不同字符串。 --- # 第一百四十五章 V1.0不需要复杂状态机框架 无需引入: - Temporal - Camunda - 工作流引擎 - BPMN平台 当前业务使用: > 枚举 + Service规则 + 数据库约束 足够。 --- # 第一百四十六章 什么时候未来考虑工作流引擎 只有当未来出现: - 多级审批 - 跨机构复杂审批 - 大量动态流程 - 可配置工作流 才考虑。 V1不需要。 --- # 第一百四十七章 核心业务规则汇总 ## 用户进入推荐的必要条件 ```text 已登录 + 已绑定手机号 + 已实名 + 资料审核通过 + 账号正常 + 婚恋状态允许 + 隐私允许 ``` --- # 第一百四十八章 用户聊天必要条件 ```text 双方互相喜欢 + Match有效 + Conversation有效 + 双方账号正常 + 双方未拉黑 ``` --- # 第一百四十九章 红娘推荐必要条件 ```text 服务有效 + 候选人审核通过 + 双方账号正常 + 双方未拉黑 + 双方Required条件不冲突 ``` --- # 第一百五十章 活动报名必要条件 ```text 活动开放 + 用户实名 + 资料审核通过 + 账号正常 + 年龄符合 + 未重复报名 + 名额可用 ``` --- # 第一百五十一章 成功牵手必要条件 ```text 有效Match + 一方发起 + 另一方确认 + 双方账号有效 ``` --- # 第一百五十二章 风控最高优先级原则 任何业务规则都必须让位于: > 用户安全。 即使用户: - 已匹配 - 已报名活动 - 已有红娘服务 一旦确认严重风险: 平台有权: - 暂停功能 - 停止聊天 - 停止活动参与 - 进入人工处理 同时保留申诉机制。 --- # 第一百五十三章 用户自主决定原则 任何系统和工作人员都不能替用户: - 喜欢某人 - 开启聊天 - 确认成功牵手 红娘和算法: > 只能推荐与辅助。 最终决定: > 永远属于用户本人。 --- # 第一百五十四章 隐私优先原则 如果隐私设置与推荐规则冲突: > 隐私设置优先。 例如: 用户关闭: ```text visible_in_search = false ``` 即使匹配分100: > 也不能出现在主动搜索结果。 --- # 第一百五十五章 V1.0最终状态机总图 ```text 用户注册 ↓ 实名 ↓ 完善资料 ↓ 人工审核 ↓ 审核通过 ↓ 正在寻找 ↓ 系统推荐/主动搜索/红娘/活动 ↓ 喜欢 ↓ 双向喜欢 ↓ 聊天 ↓ 正在了解 ↓ 成功牵手 ``` 任何阶段都有安全旁路: ```text 举报 ↓ 风险审核 ↓ 限制 / 暂停 / 封禁 ``` 任何阶段用户都可以: ```text 暂停寻找 或 退出婚恋服务 ``` --- # 第一百五十六章 最终设计原则 整个V1.0必须做到: > **每一个状态都有明确来源。** > **每一次状态迁移都有前置条件。** > **每一个关键动作都能防重复。** > **每一种异常都有明确恢复方式。** > **任何并发都不能制造重复Match、重复报名、重复消息。** > **任何后台状态变化都能及时影响用户端。** > **红娘、活动、系统推荐不能突破用户本人设置的硬条件和自主决定权。** > **账号安全与隐私规则永远高于普通业务便利性。** 最终目标不是把状态机设计得复杂,而是保证: > **任何一个异常情况发生时,系统都知道“现在是什么状态、下一步允许做什么、禁止做什么、怎么恢复”。**