2 Commits
Author SHA1 Message Date
Henry_Du d1b643bd93 refactor(微信订阅): 重写订阅消息链路,每一步失败都可见
把「微信订阅消息」这套代码按验收标准推翻重写:用户能自己看懂为什么收不到,
任何一步失败都必须看得见。对外函数名不变,notificationService / test-subscribe
等调用点无需改动。

新增 server/utils/wechatSubscribeTemplates.ts(纯函数,零依赖):
  - 模板登记表唯一来源(内置 SONG_SELECTED / SONG_REJECTED),服务层不再自己写死
  - parseSubscribeTemplates 如实报告环境变量覆盖情况:坏 JSON 只报告不抛、
    只给 id 时沿用内置字段映射、缺 id 的项记进 unknownKeys 并忽略
  - findEmptyFields / findEmptyDataFields 发出前自查空字段(微信空值整条 47003)
  - explainWechatErrcode 把 43101/47003/40003/40037/40001/45009 翻成人话

重写 server/services/wechatSubscribeService.ts:
  - sendWechatSubscribe 返回 SendOutcome,用 stage 明确「卡在哪一步」:
    no-template / disabled-by-user / no-wechat-openid / no-access-token /
    empty-field / no-grant / rejected-no-quota / rejected-bad-field / rejected-other
  - 每一次返回都写一行日志,不再有静默跳过(这是「发不出去全靠猜」的根因)
  - inspectWechatSubscribe 只读体检:不发消息、不消耗额度,返回逐项 verdict + actions
  - grantWechatSubscribe 依靠新增的 WechatSubscribeGrant 表记账:微信没有查询
    剩余授权的接口,只能自己数(用户点允许 +1、发送成功 -1)
  - 记账表不可用时失败开放(fail-open):额度预检关闭、照常发送,避免通知整体哑掉
  - access_token 显式 responseType: json 并做字符串兜底解析

新增接口:
  - GET  /api/user/wechat-subscribe-status   小程序显示「还能收到几条 / 为什么收不到」
  - POST /api/user/wechat-subscribe-grant    小程序授权成功后上报 accept 的模板
  - GET  /api/admin/wechat/diagnose          重写:人话结论 + actions,?send=1 真发一次

其他:新增 WechatSubscribeGrant 表(schema + 手写迁移)、.env.example 说明 JSON 覆盖
写法、.gitattributes 补 *.sql eol=lf。

测试:新增 test/wechatSubscribeTemplates.test.mjs(13 个用例,可直接 import .ts,
不依赖 Nuxt 别名),npm test 里订阅相关 25/25 通过。
2026-10-11 16:02:33 +08:00
Henry_Du 5962df638d ci(deploy): 工作流从 4 个 job 精简为 2 个,并启用 BuildKit registry 构建缓存
- 删掉 preflight(npm ci + nuxt build)与 meta-warmup:Dockerfile 自己在容器内
  跑 npm ci + node scripts/memory-build.js,这两个 job 的产物从来没被 docker build
  用到,纯白烧 3-6 分钟,meta-warmup 还在 build-image 之前抢同一个 runner 的内存。
- 删掉每个 job 各自跑的 apt 换源 / 清华镜像 / git URL 重写:对镜像构建没有任何影响。
- buildx 从「装不上就硬失败/一大段兜底脚本」简化为「装得上就用(带 registry 缓存),
  装不上就退普通 docker build」,部署永不因 buildx 缺席而失败。
- 新增 BuildKit registry 缓存(--cache-from/--cache-to type=registry,tag :buildcache):
  依赖安装层跨 run 复用,第二次之后的部署会快很多。
- 镜像标签改在 build-image 内计算(原先依赖 meta-warmup 的 outputs)。
- 新增 .gitattributes 强制 yml/sh 用 LF(core.autocrlf=true 会把 heredoc 写坏)。
2026-10-11 00:14:22 +08:00