App 领域:应用模型、AppKey 与推送策略
如果你只从“技术实现”角度看 App,它就是一个配置表:选 channelId、生成 appKey、存一些枚举。
但从“产品形态”角度看,App 才是这个系统真正对外售卖的能力:
我给你一个
appKey,你以后只要curl这个 key,就能稳定地把消息推到你绑定的微信。
所以 App 的设计要解决三个问题:
- 对外:怎样做到“调用方极简”?
- 对内:怎样做到“数据可关联、可追踪”?
- 对未来:怎样做到“可扩展推送策略/平台而不推倒重来”?
实现集中在:
node-functions/services/app.service.ts
App 到底是什么(一个数据模型图)
erDiagram
CHANNEL ||"--o{ APP : uses
APP "||"--o{ OPENID : binds
APP "||--o{ MESSAGE : produces
CHANNEL {
string id
string type
object config
}
APP {
string id
string key
string name
string channelId
string pushMode
string messageType
string templateId
}
这张图揭示了一个关键点:
appKey是对外入口appId才是内部主键,用来串起 OpenID 与 Message
App 的职责:把“推送策略”变成一个可配置的开关
App 并不只是一把 key,它还封装了推送策略:
- 关联哪个
channelId - 推送模式:
- single:只推给第一个绑定用户(适合个人)
- subscribe:推给所有绑定用户(适合群组/团队)
- 消息类型:
- normal:客服消息(文本)
- template:模板消息(需要 templateId)
这个组合的价值在于:
/send的调用契约保持不变(title/desp)- 但你可以在后台切换“怎么推”
AppKey 的索引策略:让 send 路由 O(1)
推送入口只拿到 appKey,所以必须能快速定位 App。
KV 中常见两类 key:
APP(id) -> AppAPP_INDEX(appKey) -> appId
这是一种非常经典的 KV 设计:
appId是主键,适合做关联appKey是外部索引,适合做入口查找
如果你只存 APP(appKey) -> App,短期也能跑,但长期会遇到:
- AppKey 轮换变麻烦
- 关联对象无法稳定引用
数据校验:把运行时异常提前到写入时
在创建/更新时做强校验,是为了让 /send 永远保持“傻瓜接口”:
name非空channelId必填且存在pushMode必须在枚举内messageType=template时templateId必填
这相当于在系统里建立一个原则:
尽量让错误发生在“配置阶段”,不要发生在“推送阶段”。
启发:对外接口越简单,内部模型越要稳定
- 让调用方简单(
curl)的代价,是你要在内部做更多“索引、校验、关联”。 appKey是入口,appId是事实主键,这种双键结构非常适合 KV 存储。
