Commit Graph

107 Commits

Author SHA1 Message Date
浅念 c7b3ce9d1c fix(analytics): 词库单字MySQL预览拒扫+IntegrityError 409+MATCH短语净化
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 19:48:30 +08:00
浅念 0c14be0777 feat(analytics): C1 敏感词库 CRUD+加词预览——防一加就淹没
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 19:32:35 +08:00
浅念 1e0db3913c fix(analytics): unreplied is_send守卫防漂移假行+真预算注释+501候选分支测试
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 19:22:22 +08:00
浅念 52af531598 feat(analytics): B2 该回未回——尾部判定/有效类型/通话豁免/已删剔除
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 19:00:15 +08:00
浅念 247bfc7277 fix(analytics): churn 排序决胜列+active_days去重日+边界测试
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 18:45:34 +08:00
浅念 3b4254639d feat(analytics): A3 流失预警三分法——真流失/从未激活/待交接
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 18:25:08 +08:00
浅念 6790710965 test(analytics): overview channel 非法值 422 断言补齐
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 18:16:44 +08:00
浅念 b067d690f1 feat(analytics): /overview 端点+unmapped_accounts 标注字段
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 18:04:05 +08:00
浅念 ad153aa2f7 fix(analytics): 环比同期对齐口径+趋势窗校验+异常新员工明细
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 17:34:14 +08:00
浅念 02e100849b fix(analytics): anomaly回退同人多账号累加+今日无环比断言修正
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 17:17:24 +08:00
浅念 49f2ffe8ea feat(analytics): A1 总览指标——卡片/首沟通口径/周月环比/异常警示/空表回退
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 17:05:57 +08:00
浅念 af05e58976 perf(analytics): 5表 updated_at 窄索引——health MAX 消除全表扫(128MB buffer pool)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 16:40:01 +08:00
浅念 5b6a9bd35b fix(analytics): recompute_all 全表清空自愈+whatsapp/多日/空日测试+映射缓存
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 16:28:39 +08:00
浅念 e3bb97bdf3 feat(analytics): stat_daily_staff 员工日汇总维护层——rollup派生/幂等/判别法
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 16:06:18 +08:00
浅念 4cfc2fa6a9 test(analytics): health 契约加深——ISO 序列化断言/空库6实体/诊断端点500有意注释
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 16:00:38 +08:00
浅念 0b1d377db7 feat(analytics): E0-lite 数据健康端点——数据截至+实体新鲜度
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 15:37:13 +08:00
浅念 565006239b feat(analytics): 数据分析板块四新表+迁移——stat_daily_staff/敏感词三表/fetched_at 索引
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-04 15:04:33 +08:00
浅念 5cfc09121a feat(scraper): cookie 过期自动续期——浏览器表单重登+缓存+整实体重跑
撞 CookieExpiredError → PageScraper 表单登录(密码登录tab+placeholder选择器,
2026-09-03 实测一次成功)→ 新 cookie 落 MEDIA_DIR/.yk_cookie_cache(优先于
compose 注入的 env,永远比它新)→ 实体重跑一次(幂等+水位,安全);二次过期
直接抛出防循环;重登失败(无账密/云客改版)报可读原因退出码 3。

main 瘦身:cookie 加载收敛 _load_cookie(缓存>env>settings),分发链移
_dispatch_entity。测试 8 新增,全量 525 绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 18:11:26 +08:00
浅念 e365108244 fix(scraper): 云客鉴权失败信封统一拦截——cookie 过期响亮报错不再静默
事故(2026-09-03 手动同步实测):cookie 过期时 WA 路径对 str data 调 .get
崩 AttributeError,微信路径更糟——auth 错误信封被当空数据,55 员工全部
rows=0 无任何告警,整轮同步一无所获。

守卫:_browser_fetch 收口统一走 _check_auth_envelope,识别 success=false
且 code=±20020(实测信封)抛 CookieExpiredError;main 入口捕获后输出
一句话可读信息 + 退出码 3(不再天书堆栈)。业务错误(-90000 等)不受影响
照旧放行。测试 5 新增,全量 517 绿。

后续(等确认真实密码):CookieExpiredError 触发自动重新登录换 cookie,
过期彻底自愈。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 17:52:09 +08:00
浅念 421998be54 perf(api): 会话/5数字弹窗超时修复——日粒度汇总层 msg_daily_stats
根因(服务器实测):sessions 对 owner 全量 message GROUP BY,重账号 5.2万条
3~5s;staff-chat-stats 全时段窗 6.9s——128MB buffer pool 下被推过前端
15s 超时(ECONNABORTED)。EXPLAIN ANALYZE 证实最优 covering 索引也要
18.9s,瓶颈是磁盘不是查询形状。

修复(预聚合,云客同款思路):
- msg_daily_stats 表:每「渠道×账号×会话×上海自然日」一行(收发计数/
  当日最后时间与方向);迁移 a7d3e9f1c2b4(幂等建表)
- 写路径:repos.upsert_messages 落库自动重算本批触及的会话×天(所有
  抓取路径汇到该函数,一处挂全;失败不阻塞写入)
- 读路径:sessions/staff-chat-stats 表有行时读汇总(namedtuple 同形,
  端点主体零改动),空表守卫回退旧聚合(部署回填前不空白)
- 自愈:CLI daily-stats 全量重建(幂等);full_sync_all.sh 夜间追加第 11
  步——顺带修掉尾部 sqlite3 直连 smoke.db 的硬编码(服务器 MySQL 上会炸)
- 口径统一:day 一律 Asia/Shanghai Python 计算(旧 from_unixtime 跟随
  DB 会话时区与今日数割裂);统计窗口对齐自然日(文档化语义变化)

测试:12 新增(汇总层 8 + 端点判别/对拍 4,判别手法=回填后删光 message
仍出完整数据),全量 512 绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 16:37:36 +08:00
浅念 6880ff1b97 feat(auth): 登录页(用户名/密码换 API token)+ 前端全链路登录态
后端:
- POST /api/auth/login:admin 账密(Settings 默认 admin/admin123,
  ADMIN_USER/ADMIN_PASSWORD 可覆盖)换取共享 api_token,免 token 中间件
- 防爆破:同 IP 15min 窗口内 5 次失败锁 15min(429),成功登录清零
- 错误信息统一「用户名或密码错误」(防用户名枚举)
- 测试 7 个新增(TDD),全量 500 绿

前端:
- LoginView + 路由守卫(未登录跳 /login,回跳 redirect)
- axios 请求拦截器自动带 Bearer;401 清登录态回登录页
- 媒体直链统一 mediaUrl() 带 ?token=(img/audio 标签发不了 header),
  替换 4 处裸拼;downloadBlob 手动带头
- isLoggedIn 按 key 存在判定 — 后端鉴权关闭时空 token 不锁死登录页
- MainLayout 侧栏底部退出登录

compose:两份编排透传 ADMIN_USER/ADMIN_PASSWORD(默认 admin/admin123)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 15:03:20 +08:00
浅念 ef7f6d8a23 fix(migrate): 类型迁移SQLite内联修复FTS触发器+多owner群room_id测试+DEPLOY补stamp依据与锁表提示
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 20:55:18 +08:00
浅念 35bfebd3e3 chore(backend): list_order迁移补齐+Task14类型修正落链+moments每页日志+MsgTypeParam派生+3处文档修正+Dockerfile打包migrations+DEPLOY补迁移步骤
- 9b0d0c133035: wechat_account.list_order 进迁移链(此前仅模型声明,
  干净库 /api/accounts 即 500);sa.inspect 幂等守卫兼容已手动加列的
  smoke.db
- fe63c6789e94(验证中发现的预存缺口,超出原清单): Task 14 的 5 列模型
  类型修正(4×URL String(1024)→Text, db_size Integer→BigInteger)从未落
  链——纯 alembic 新库会复活 >1KB 链接截断;对齐后干净库 alembic check
  全绿。SQLite message 表 batch 重建会掉 FTS 触发器+rowid 脱节(docstring
  记明 ensure_fts+rebuild_fts 修复,smoke.db 已修复验证)
- scrape_via_page: _iter_moments_pages 每页一行进度日志(镜像 _fetch_pages)
- messages: MsgTypeParam=Literal[tuple(_MSG_TYPE_FILTER)] 派生,杜绝
  双处罗列漂移(openapi enum 验证一致,492 绿含 422 行为)
- 文档: ChatGroup 复合PK docstring/groups room_id 多行表述/测试名去
  单行假设;Dockerfile 补 alembic.ini+migrations;DEPLOY 增「数据库
  迁移」节(新库/旧库stamp路径/回填脚本显式DB_URL)+运维表升级行

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 20:32:25 +08:00
浅念 1b66be6a53 feat(api): /api/customers 加 q 文本搜索(昵称/备注/ID/手机号,LIKE转义) + /api/groups 加 q 群名搜索
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 18:55:53 +08:00
浅念 4baa8639ba fix(api): staff-stats评审修复(GROUP BY显式列防ONLY_FULL_GROUP_BY/金额千分位/detail死参数/2边缘测试)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 16:36:07 +08:00
浅念 b95fc5fa6f feat(api): GET /api/staff-stats 7类计数+分型明细(voice走user_id join,新客户add_time兜底,红包金额提取)
计数模式(无kind)返回 new_customers/new_groups/red_transfer/del_customers/
blocked_customers/voice_calls/sensitive_words(恒0,spec占位);明细模式
(?kind=)返回{kind,rows},每kind字段不同,前端按kind配列。start/end
缺省近7天。

口径(spec §4.5,全本地聚合):
- new_customers: add_time窗内;IS NULL行用该对话首条消息min(timestamp)兜底
- new_groups: chat_group.create_time窗内(复合PK按owner过滤)
- red_transfer: wechat type IN (red_packet,transfer)窗内;金额三路正则
  (红包XML feedesc/转账纯文本/totalamount),实测真库转账399/399全提取
- del/blocked_customers: 现存量口径忽略窗口,明细time=updated_at毫秒
- voice_calls: phone_call.user_id存员工userId(32HEX)非wxId——先经
  wechat_account.user_id换算,账号无uid返回空防跨员工串数
- voice明细字段语义对齐CallList.vue(connected=call_status==1,
  media_url本地/api/media/{hash}优先OSS兜底)

真机smoke(yunke-mysql):voice 61条/新客67/删除29/拉黑1均通过;
转账金额100%提取。真库chat_group列与message.type回填滞后(运维项,另报)。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 16:22:44 +08:00
浅念 2baa6d0814 test(moments): 同create_time并列时按id升序tiebreak测试(锁分页稳定契约,任务6评审遗留)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 16:22:44 +08:00
浅念 b289aa2650 fix(api): sessions is_del 越界422校验+省略不过滤显式契约测试
is_del 加 Query(ge=0, le=1)——越界值(如2)422 拒绝而非静默空列表;
test_sessions_is_del_filter 追加第三个请求:不带 is_del 时全部 4 个
talker 都返回(f1/f2/filehelper/gh0st),补上省略=完全不过滤的显式契约。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 15:57:59 +08:00
浅念 2837500bc0 feat(api): GET /api/moments 朋友圈列表(desc分页+账号头部)
对齐云客员工聊天窗口朋友圈tab:帖子 create_time desc 分页 +
wechat_account 头部(昵称/头像/别名);员工不存在不404(header全None
前端兜底)。头像提取抽共享 helper account_avatar 放 organization.py,
accounts 列表与 moments 头部复用。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 15:57:53 +08:00
浅念 d3d7146887 feat(api): sessions加is_del过滤+filehelper置顶标记,accounts加avatar(raw_json提取)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 15:44:54 +08:00
浅念 64577a1b02 feat(msg): 类型归一化扩展(spike判别+49拆红包/转账)+存量回填+API msg_type/q过滤
- _normalize_msg_type 升级 (raw_type, row): messageType 经典码优先 →
  49/appmsg 行级拆分(红包/转账/聊天记录) → 云客码兜底
- spike 修正: 云客 type=3 实为语音(messageType=34, 8754/8955 行),
  原 image_legacy 是误标; type_raw=3 的 201 行旧数据才是真图片
- 新映射: 5红包 6/7通话 9文件 10/18/20链接 11转账 13名片 14位置
  15/10000系统 21引用回复→text 22/19 证据不足留 unknown
- 回填 smoke.db: 620279 行重扫, 94268 行修正, unknown 87198→1885, 幂等
- GET /api/messages 加 msg_type(Literal 422)+q(LIKE 转义)参数
- 新增 test_scrape_msg_type.py(11) + test_api_messages 追加(8), 全量 466 绿

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 15:17:21 +08:00
浅念 f6ddd0263a fix(repos): int 强转跳过 String 声明列(列类型优先于 _INT_FIELDS 按名集合)
Task 1 评审遗留:_INT_FIELDS 含 type_raw(为 Message int code 加),但
MomentsPost.type_raw 是 String(16)——按名强转会把非数字 code(如
'text')置 None,违背列声明。_build_column_values 现在检查目标列
声明类型:isinstance(col.type, sa.String)(含 Text)则跳过强转,
Message.type_raw(Integer) 照旧。另修正 upsert_chat_group 文档串里
过时的 'PK = room_id'(复合键自 8a99940)。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 14:32:19 +08:00
浅念 6ff288f1d3 feat(groups): chat_group 补 6 群主/建群列 + 复合PK迁移修复 + 存量回填
对齐云客员工聊天窗口·微信群 tab(2026-08-25 真机验证 raw_json 键):
- ChatGroup 加列 owner_name/owner_wxid/owner_alias/owner_avatar/
  friend_count/create_time(全 nullable)
- scraper _normalize_chat_group 同名提取;createTime 兼容 ms-int 与
  'YYYY-MM-DD HH:mm:ss'(smoke.db 实测 1105 行全为后者),复用
  _parse_add_time 归一 ms-epoch
- 迁移 099ac2097fa2:加 6 列 + 修复 Task1 评审遗留 drift——PK 由单列
  room_id 变更为复合 (room_id, channel, owner_account_id) 且
  owner_account_id NOT NULL(对齐模型 8a99940;smoke.db 1105 行无 NULL,
  未兜底编造数据);SQLite 走 batch 重建(copy_from 显式旧结构),
  MySQL 渲染为直接 ALTER(离线 --sql 已验证)
- 回填脚本 scripts/backfill_chat_group_fields.py(幂等,逐列只补空);
  smoke.db 实跑 backfilled 1105/1105,重跑 0/1105
- GroupOut 加 6 字段(model_validate 自动输出,路由无改)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 14:32:12 +08:00
浅念 90c28f4c7b feat(scraper): moments 实体(浏览器fetch getFriendsterInfo,秒→ms,hashNext翻页,接入full_sync+4h调度+图片media)
- scrape_via_page:_normalize_moments(createTime秒×1000,缺id丢弃)+
  _iter_moments_pages 翻页内核(fetch回调注入,sleep可注入,hashNext假/
  信封异常/max_pages 上限即止)+ scrape_moments(逐员工遍历wechat_account,
  form小驼峰,首页code≠10000告警cookie失效,换页重试惯例)+CLI注册moments
- media:download_moments_images(image_urls JSON数组展开去重,MomentsPost无
  回链列→用Media.original_url做已下载标记,分片IN防SQLite变量上限,批间commit)
  接入scrape_media第4源
- full_sync_all.sh:9c步moments(media前,同轮图片即可本地化)+汇总加moments计数
- scheduler:4h messages job 末尾追加 moments --max-pages 3 浅扫(全量翻页
  由每日full承担);测试断言7条命令序列
- tests/test_scrape_moments.py:归一化(秒→ms/空安全/坏createTime)+翻页内核
  (两页累积停止/hashNext假单页/max_pages防死循环/丢id行/坏信封)+图片本地化
  (一帖两图/幂等跳过/非http跳过+500容错);全套440测试通过

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 14:07:39 +08:00
浅念 b7669199f8 feat(db): moments_post 表+upsert(朋友圈实体,PK=云客data.id,create_time统一ms)
- MomentsPost 模型:moments_post 表,PK=id(云客 getFriendsterInfo data.id),
  wechat_id/create_time 建索引,praise/comment/image 存 JSON 列
- 迁移 524da8d2d597(手写 create_table,已应用到 smoke.db 并在临时 SQLite
  全链路 upgrade/downgrade 验证)
- repos.upsert_moments_posts:批量幂等 upsert;附带修 _build_column_values
  对 JSON 列表的误 join(标量列 join 保持不变,dept_route 旧测试仍过)
- 修复 3 个 chat_group 旧测试缺 owner_account_id(2026-08-24 复合主键遗留)
- 全套 430 测试通过

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 13:44:54 +08:00
浅念 a8b8d9d81c fix(export+calls): 同类owner错位问题全面修复(群导出不按owner过滤+群语音客户点击走群聊路由)
- /api/export/chat-html: room 查询忽略 owner(chat_group owner 错位同
  ChatTimeline,群列表/聊天页的导出按钮原来会导出空文件)
- CallList viewCallCustomer: talker 以 @chatroom 结尾→group-chat 路由
  (原走 1:1 路由按 talker_id 查@chatroom 恒空)
- TDD: 群消息在 ownerB 名下用 ownerA+room 导出仍能拿到;428 测试绿
- 实测:错位 owner 导出 43304 群返回 15002 个消息元素

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-22 17:00:43 +08:00
浅念 a290e39523 feat(customers): 发送/接收列改今日口径(对齐云客;本地消息表Asia/Shanghai今日聚合)
- CustomerOut 加 send_today/receive_today(路由赋值,非ORM列)
- /api/customers 每页一次 GROUP BY(owner IN 走复合索引前缀)
- 前端列优先今日值,无消息数据回退原raw字段;列名对齐云客「发送条数/接收条数」
- TDD:今日3发2收+昨日不计入+无消息客户0

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-22 14:39:17 +08:00
浅念 94c2df4612 test(scheduler): 更新messages job断言(四类消息命令序列)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-21 15:17:40 +08:00
浅念 e8c77412fa feat(search): FTS5 trigram全文索引(中文搜索3.95s→0.003s,1300倍)
- message_fts 外部内容虚拟表+trigram分词(中文子串可MATCH,无需分词库)
- 3个触发器随ORM upsert自动同步索引(抓取器零改动)
- 搜索路由:≥3字走FTS MATCH,<3字/MySQL回退LIKE
- 实测:搜「大众途安」56条,LIKE全扫3.95s→FTS 0.003s;索引+300MB
- 7个新测试(建表幂等/触发器同步/中文匹配/短查询回退/未建索引回退),426绿

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-21 15:08:26 +08:00
浅念 621c2cc929 feat(scheduler): 每周日05:00全量对齐job(四消息实体--full-history,修撤回/编辑+消除滞后窗口)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-21 13:52:59 +08:00
浅念 edca9b4c77 fix(customers): WA客户破1万上限(逐员工uid过滤,8585→11931全量)+双渠道页脚云客口径+消息同步刷新最近沟通时间
- wa-friends 逐员工抓取:全局查询~1万行硬上限(云客11931只翻到10000),
  uid=员工WA号过滤(真机验证 declared 1145→1149),total-aware翻页
- declared-total 分渠道:Σ wechat/whatsapp_account.contacts_num(8590/11915)
- 消息增量同步顺带刷新 customer.last_chat_time(云客列表按最近沟通实时
  排序,快照每日一次导致顺序滞后;微信1:1+WA都加)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 14:04:06 +08:00
浅念 fd3cf0003b feat(customers): 微信客户页脚改云客口径(Σ员工好友数声明值8590,用户选B方案)
- GET /api/customers/declared-total: Σ wechat_account.contacts_num
- 页脚优先显示云客口径(回退真实total);列表内容保持去重真实行
- 云客列表声明值含其ES索引重复doc(连行id都相同无法物理区分),仅对齐计数

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 13:44:39 +08:00
浅念 4aeed003a4 feat(calls): 微信语音列表加今日统计卡片+通话时间范围筛选+客户跳转带通话时间定位(对齐云客)
- GET /api/calls/stats:今日(Asia/Shanghai)好友呼入/外呼量+群量+时长聚合(@chatroom判群)
- CallList:5张统计卡片(仅微信语音tab)+datetimerange筛选(服务端start/end)+viewCallCustomer带?start定位
- TDD新增stats聚合测试,全量绿

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 11:08:13 +08:00
浅念 6c9245a682 fix(groups): /api/groups加room_id精确直查(群聊页群名解析,修page_size=200超限422)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 10:58:39 +08:00
浅念 1d90829754 feat(scraper): WA群消息抓取(chatRecords friendUid=@g.us,chatRoomTalker=群内发送者)
- 真机探明:同 chatRecords 端点 friendUid 直接传 @g.us 群id(与微信群同套路)
- 群行 chatRoomTalker=发送者@lid、keyId 有值(缺失时合成稳定主键)
- file 字段直连 OSS URL 优先于 mediaName(WA群媒体 URL 现成!)
- 守护循环同微信群;full_sync 加 9b 步;3 新测试,416 绿

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 10:54:09 +08:00
浅念 5923cd05b1 feat(scheduler): 定时同步全面页面化(子进程跑页面脚本,API直调退出调度防风控)
- 每日 full: bash scripts/full_sync_all.sh;每4h messages: scrape_via_page --entity messages
- 子进程隔离+asyncio.Lock互斥+非零退出只记JSON日志;自动补DB_URL环境
- ENTITY_FUNCS/run_once/CLI保留为手动调试,不再挂定时触发器
- README同步更新(Docker镜像需Playwright+Chromium);413测试绿

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 09:33:53 +08:00
浅念 f92aac1a3d feat(scraper): 微信群消息抓取(368778条/750群)+浏览器守护循环+SQLite忙等
- 新 group-messages 实体:真机探明群消息=同一 msg/chats 端点 friendId 传 roomId;
  talker=发送者wxid、msgId=null→owner:room:createTime:talker 合成稳定主键(重扫幂等)
- 浏览器守护循环:超大群撑崩渲染进程时重启浏览器跳过毒群继续(实战2次自愈);
  200页上限;恢复路径补 await
- base.py SQLite connect_args timeout=60:并发写忙等而非撞锁报错
  (双抓取器并发写实测 database is locked 崩任务)
- 5个新单测,全量410绿

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 09:09:32 +08:00
浅念 ab5a918a3b fix(calls+scraper): 语音群scope服务端过滤+对话发现缺口补全+抓取韧性三连修
- /api/calls 加 scope=friend|group(@chatroom后缀判群,与isRoom实测等价120=120),CallList去掉「全部」tab改服务端查
- 对话发现:全部customer pair ∪ 语音pair(weChatId,talker),未扫过的排最前——修复纯语音关系客户聊天记录永远空(35%语音客户pair从未扫过)
- voice-calls改浏览器直发(isRoom=0/1双趟+WA callSource=4,拦截方式已两次失效)
- 断连恢复重试30×2min(云客约3h一次断连,已实战扛过多次)
- WA messages upsert改整列表直调(_upsert_all逐条传dict被迭代成key字符串→TypeError)
- 405测试绿含scope新增3个

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-19 16:48:22 +08:00
浅念 f9ed7dd821 feat(scraper): 微信消息翻页取完整历史(paginate_chats hasLast/end游标+200页上限,移除临时skip;全量回填3478对话+95361条至2025-10)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 09:15:04 +08:00
浅念 2d1943a74e fix(api): 客户/群排序改回last_chat_time DESC(云客按最近沟通优先)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-15 14:18:42 +08:00