Files
kefu/deploy/my-customers-20260918/my-customers-audit.md
T
2026-09-21 10:34:06 +08:00

6.8 KiB
Raw Blame History

医疗助理“我的客户”数据源只读审计

时间:2026-09-18。审计目录 C:/wechat_rpa 及 C:/Users/isard/AppData/Local/ZhenYangTangRPA 已存在的解密缓存。已通过现有 active_context → discover → NativeClient(write=False) 只读核验当前企微账号;未发送消息、未重新解密、未打开原企微数据库、未修改产品文件。报告只含 schema 和聚合计数,不含客户姓名、手机号、客户 ID 或消息正文。

明确问题

当前医疗助理选择列表不是“企微通讯录→我的客户”:

  • review_assistant_contacts.py:224 只从历史 message_table 选 M:% 会话。
  • 第 196 行虽然读取 external_user_relation_v3,但只用于补充名字,不据此限定客户归属。
  • 第 260 行追加所有 wechat_contactV1 微信通讯录条目,与企微客户关系没有必然对应。
  • 第 21、305 行只允许 M:;当前缓存的两条企微关系联系人均为 S:,被整个漏掉。
  • review_assistant.py:95 同样只接受 M: 医疗助理接收人配置。仅修改列表,S: 选择仍无法启用,需同步调整校验与相应用例。此处只报告,未修改。

当前账号实测

安装版采用当前账号目录内最新的 archive_auto_backup/decrypted user/session/message 缓存,修改时间约 09-18 10:16;源码目录缓存相对更旧,但关键客户关系计数一致。

数据 安装版最新缓存数量 说明
user.db / user_table 172 包括当前企业员工,不能整体当客户
user_table 与当前账号同 corp_id 168 是用户缓存,不是“我的客户”成员表
user.db / external_user_ids 4 外部用户集合,含 2 条没有当前账号关系行
user.db / external_user_relation_v3 2 两条均在 external_user_ids,且能 join user_table
user.db / wechat_contactV1 214 微信通讯录,不应作为我的客户主列表
user.db / wx_friend 0 当前没有显式 UID↔wx_id 映射,不能将214条微信通讯录直接转发送地址
session.db / conversation_table 96 S:17,M:1,其余为其他会话类型
message.db / message_table 699 仅统计数量;未查询正文
关系联系人→已有S会话 2 两条都包含当前账号及唯一对端,且都有历史消息
关系联系人→M会话 0 旧M列表漏掉全部关系联系人

两条关系的 status 分别为 2049 和 2057,stranger_type 均为 0,create_time/add_customer_time/remark_time 均大于 0。两条均有 user_table.name 昵称;real_remarks/remarks/corp_remark/recommend_remark 均为空。删除关系表 delete_external_userV1 和黑名单表 blacklist_external_userids 当前均为 0。

哪张表应作为主源

应以**当前已核验账号目录里的 user.db.external_user_relation_v3**作为归属关系的主源,再以 user_id = user_table.id 取名字和身份。该表含 status、stranger_type、add_customer_time、客户来源、客户备注等与本账号关系相关字段;现有归档代码 archive_auto_backup.py:830 也用这张关系表限定 wecom_external_local_uid,不会把全体同事当外部联系人。

external_user_ids、全体 user_table、历史单聊集合、微信通讯录均不能独立证明“是当前账号我的客户”。实测 external_user_ids 比关系表多 2 条,正是不能直接并入的证据。

边界:尚不能仅凭这份缓存证明与企微实时UI完全相同。 客户关系 status 是组合标志,现有代码没有 2049/2057 的定义,实测样本也不足以推导每个位意义。不能猜测 status==1、status!=0 或某个位来断言关系当前仍有效。关系表可以提供明确归属候选,但若要求严格排除已删/待确认关系,需要有经过验证的状态定义或只读UI对照,不能用历史消息或姓名推断。

ID、名称与可发送会话映射

  1. 使用关系表的数值型 user_id 作为本地外部联系人 UID,作用域包含当前账号。它不等同于官方 API 的字符串 external_userid,不能互换。user_table 有 unionid 字段,但当前表结构没有明确官方 external_userid 字段;本轮没有解码不透明 protobuf 字段。
  2. 展示名字优先读取 real_remarks → remarks → user_table.name → user_table.real_name;名称只用于展示和搜索,不作为身份、去重或发送地址。当前两条需要回落到昵称。
  3. 从已经存在的 session/message 会话里匹配 S::格式 S:<uid1>_<uid2>,必须恰有一端等于当前账号、另一端等于关系 UID。当前两条均通过该映射,未发现歧义。保留数据库里的原始会话 ID,不自行猜拼接或依赖名字。
  4. M: 只有在对端 UID 与关系 UID 有明确对应时才可候选;当前样本为 0。wechat_contactV1.gene 不能猜作 UID;wx_friend 当前为空,不具备214条微信通讯录到会话的可靠映射。
  5. 客户归属与可发送性应分开:有关系但没有可核验会话的客户仍可展示为暂不可选,不应要求先出现消息才能成为“我的客户”;已映射会话也不能据此保证对端现在接受消息,发送前仍应保留当前账号校验与联系人限制检查。

session.db 还存在 crm_customer_conversation_relation2、inner_customer_conversation_relation、outer_customer_conversation_relationV2,当前均为空,不能作为当前列表来源。user_extend.db 仅同事备注、休假相关表,没有更完整的我的客户表。

联系人限制记录

源码目录 contactBlocked 为 0,unrepliable_sessions 为 0。安装版 contactBlocked 有 1 条,可在内存中按账号+会话哈希匹配到一个 S: 关系联系人,关系 status=2049,但记录已超过现有 6 小时有效期。该记录是曾经不能回复的证据,不能用来定义 status=2049 的含义,也不能作为永久删除关系的依据。

现有 contact_reply_guard.py 根据系统验证提示/明确传输拒绝识别限制,protocol_engine.py:354 维护短期屏蔽;这些记录是发送保护,不是我的客户名单。医疗助理列表应共享保护结果,不能用屏蔽名单反推出全部客户。

交付与限制

  • schema-aggregates.json:源码缓存各表 schema 与数量。
  • relation-aggregates.json:源码当前账号关系状态、名称覆盖、S/M映射数量。
  • packaged-aggregates.json:安装版最新缓存、关系及联系人保护计数。
  • 三个 audit_*.py 为本次只读审计脚本,只读已解密缓存,输出聚合结果。

当前缓存已经具备“按本账号关系列出候选 + 显示昵称/备注 + 核验既有S会话”的关键数据;不需要为此读取消息正文或强制解密。严格实时UI成员一致性及 status 位定义仍缺证据,本审计未声称解决这些未验证问题。